Pull to refresh

Выпуск Rust 1.42.0: шаблоны срезов и более удобные сообщения о панике

Reading time5 min
Views6.9K
Original author: The Rust Release Team

Команда Rust рада сообщить о выпуске новой версии, 1.42.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.


Если вы установили предыдущую версию Rust средствами rustup, то для обновления до версии 1.42.0 вам достаточно выполнить следующую команду:


rustup update stable

Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.


Что вошло в стабильную версию 1.42.0


Основными нововведениями Rust 1.42.0 являются более удобные сообщения о панике в случае вызова unwrap, шаблоны срезов, объявление устаревшим Error::description и многое другое. Смотрите подробности выпуска для дополнительной информации.


Сообщения о панике из Option и Result теперь включают полезные номера строк


В Rust 1.41.1 вызов unwrap() для значения Option::None порождало сообщение об ошибке примерно такого содержания:


thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', /.../src/libcore/macros/mod.rs:15:40

Аналогично, номера строк в сообщениях о панике, порождаемые вызовами unwrap_err, expect и expect_err, как и соответствующими методами для типа Result, тоже ссылались на внутренности core.


В Rust 1.42.0 все эти восемь функций порождают сообщения о панике, которые включают такие номера строк, откуда они были вызваны. Новые сообщения выглядят примерно так:


thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:2:5

Это означает, что ошибочный вызов unwrap находился на строке 2 в файле src/main.rs.


Это поведение стало возможным благодаря аннотации #[track_caller]. Эта аннотация ещё не доступна в стабильной версии Rust, но если вы уже сейчас хотите использовать её в своём коде, вы можете отслеживать прогресс в этой задаче.


Образец по части среза


В Rust 1.26 мы стабилизировали так называемые "образцы по срезам", позволяющие сопоставлять с образцами на срезах. Такие образцы выглядели примерно так:


fn foo(words: &[&str]) {
    match words {
        [] => println!("empty slice!"),
        [one] => println!("one element: {:?}", one),
        [one, two] => println!("two elements: {:?} {:?}", one, two),
        _ => println!("I'm not sure how many elements!"),
    }
}

Данный синтаксис позволял сопоставлять значения со срезами, но такие образцы были достаточно ограниченными. Вам приходилось выбирать точные размеры срезов, которые вы хотели поддерживать и вынуждены были предоставлять обработку случая по умолчанию для размеров срезов, которые вы поддерживать не хотели.


В Rust 1.42 у нас теперь есть расширенная поддержка сопоставления с частью среза:


fn foo(words: &[&str]) {
    match words {
        ["Hello", "World", "!", ..] => println!("Hello World!"),
        ["Foo", "Bar", ..] => println!("Baz"),
        rest => println!("{:?}", rest),
    }
}

Синтаксис .. называется "остаточный образец" (rest pattern), потому что он сопоставляется с остаточной частью среза. Данный пример чуть выше использует остаточный образец в конце среза, но вы можете использовать такие образцы множеством других способов:


fn foo(words: &[&str]) {
    match words {
        // Игнорируем всё, за исключением последнего элемента, который должен быть "!".
        [.., "!"] => println!("!!!"),

        // `start` - это срез из всех элементов, кроме последнего, который должен быть "z".
        [start @ .., "z"] => println!("starts with: {:?}", start),

        // `end` - это срез из всех элементов, кроме первого, который должен быть "a".
        ["a", end @ ..] => println!("ends with: {:?}", end),

        rest => println!("{:?}", rest),
    }
}

Если вы заинтересовались и хотите узнать больше, мы опубликовали статью в блоге Inside Rust с обсуждением этих изменений и разные улучшений сопоставления с образцом, которые мы могли бы включить в стабильную версию языка в будущем! Вы также можете прочитать больше об образцах по срезам в статье Томаса Хартманна.


matches!


Этот релиз стабилизирует новый макрос, matches!, который принимает выражение и образец, и возвращает true, если образец сопоставим с выражением. Другими словами:


// Используя выражение match:
match self.partial_cmp(other) {
    Some(Less) => true,
    _ => false,
}

// Используя макрос `matches!`:
matches!(self.partial_cmp(other), Some(Less))

Вы можете также использовать образцы с | и условные ограничения if:


let foo = 'f';
assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));

let bar = Some(4);
assert!(matches!(bar, Some(x) if x > 2));

use proc_macro::TokenStream; теперь работает


В Rust 2018 мы избавились от необходимости в extern crate. Однако процедурные макросы оказались в какой-то степени особенными и, таким образом, когда вы создавали процедурный макрос, вам по-прежнему приходилось писать extern crate proc_macro;.


В данном релизе, если вы используете Cargo, и если вы работаете с изданием 2018, вам больше не нужна эта строка; вы можете использовать use подобно импорту из любого другого крейта. Поскольку большинство проектов уже используют импорты, подобные use proc_macro::TokenStream;, это изменение означает, что вы можете просто удалить строку extern crate proc_macro; и ваш код останется рабочим. Изменение хоть и маленькое, но делает использование процедурных макросов более органичным по отношению к обычному коду.


Библиотеки



Стабилизированные API



Другие изменения


Есть также другие изменения в релизе Rust 1.42.0: их полное описание смотрите в Rust и Cargo.


Замечания о совместимости


В этом релизе есть два наиболее значимых момента по совместимости: устаревший функционал в стандартной библиотеке и понижение 32-битной платформы Apple до уровня 3.


Error::description устарел


Ошибки иногда совершаются. Error::description теперь рассматривается как одна из таких ошибок. Проблема возникла с данной сигнатурой метода:


fn description(&self) -> &str

Поскольку метод description возвращает &str, теперь он совсем не так полезен, как мы ожидали этого раньше. То есть вам придётся возвратить содержимое значения Error буквально; если вы хотели, скажем, использовать форматирование для более удобного и дружественного к пользователю описания ошибки, это оказывалось невозможно: вам нужно было вернуть String. Вместо этого, современная практика программирования на языке Rust предполагает, что типы ошибок должны реализовывать типажи Display/Debug, чтобы предоставить возможность получения описания ошибки.


Этот API существовал начиная с Rust 1.0. Мы работали в этом направлении достаточно продолжительное время: ещё в Rust 1.27, мы объявили этот метод "немного устаревшим". Что это означало на практике это то, что мы сделали для этой функции реализацию по умолчанию. Это в свою очередь означает, что пользователи больше не вынуждены реализовывать типаж Error. В данном релизе мы на самом деле объявили его устаревшим, и предприняли некоторые шаги, чтобы ослабить значимость этого метода в документации типажа Error. Однако мы вынуждены следовать нашему соглашению о стабилизации, то есть метод description никогда не будет удалён, и объявить устаревшим — это наибольшее, что мы можем сделать в данных условиях.


Понижения приоритета для 32-битной платформы Apple


Apple больше не поддерживает 32-битные системы, так что и мы тоже не хотим. Эта платформа была понижена до поддержки Уровня 3. Детальнее об этом читайте эту статью вышедшую ещё в январе, там изложены все подробности.


Участники 1.42.0


Множество людей собрались вместе, чтобы создать Rust 1.42.0. Мы не смогли бы сделать это без всех вас, спасибо!


От переводчиков


С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов.


Данную статью совместными усилиями перевели andreevlex, funkill, Hirrolot и nlinker.

Tags:
Hubs:
Total votes 44: ↑42 and ↓2+40
Comments6

Articles