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


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


rustup update stable

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


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


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


Константные обобщения при индексации массива


Продолжая движение к стабилизации константных обобщений, этот выпуск добавляет реализации ops::Index и IndexMut для массивов [T; N] любой длины const N. Оператор индексации [] уже работал с массивами с помощью встроенной магии компилятора, но на уровне типа массивы до сих пор фактически не реализовывали библиотечные типажи.


fn second<C>(container: &C) -> &C::Output
where
    C: std::ops::Index<usize> + ?Sized,
{
    &container[1]
}

fn main() {
    let array: [i32; 3] = [1, 2, 3];
    assert_eq!(second(&array[..]), &2); // срезы работали ранее
    assert_eq!(second(&array), &2); // теперь это работает напрямую
}

const повторение значений массива


Массивы в Rust могут быть записаны как в форме списков [a, b, c], так и в форме повторений [x; N]. Повторения разрешены для длины N большей, чем один, только для x, реализующих типаж Copy, и в рамках RFC 2203 мы стремились разрешить любые const выражения. Однако пока эта функциональность была нестабильна для произвольных выражений, лишь начиная с Rust 1.38 её реализация случайно позволила использовать const значения в повторениях массивов.


fn main() {
    // Это не разрешено, так как `Option<Vec<i32>>` не реализует `Copy`.
    let array: [Option<Vec<i32>>; 10] = [None; 10];

    const NONE: Option<Vec<i32>> = None;
    const EMPTY: Option<Vec<i32>> = Some(Vec::new());

    // Однако повторения с `const` значениями разрешены!
    let nones = [NONE; 10];
    let empties = [EMPTY; 10];
}

В Rust 1.50 эта возможность признана официально, так что вы можете использовать такие конструкции без опасений. В будущем для того, чтобы избежать "временных" именований констант, вы можете использовать встроенные выражения const согласно RFC 2920.


Безопасные присвоения полям объединения ManuallyDrop<T>


В Rust 1.49 появилась возможность добавлять поля ManuallyDrop<T> в union, позволяющая таким образом использовать Drop для объединений. Однако объединения не сбрасывают старые значения во время присваивания полей, так как не знают, какой из вариантов ранее был действителен. Поэтому из соображений безопасности Rust ранее ограничивался только типами Copy, которые не используют Drop. Разумеется, ManuallyDrop<T> не требует Drop, поэтому теперь Rust 1.50 расценивает присваивания и этим полям как безопасные.


Ниша для File на Unix платформах


У некоторых типов в Rust есть определённые ограничения на то, какое значение считать допустимым, поскольку они могут выходить за границы допустимых значений диапазона памяти. Мы называем любое оставшееся недопустимое значение нишей (niche), и это пространство может быть использовано для оптимизации схемы размещения типов. Например, в Rust 1.28 мы представили целочисленные типы NonZero, такие как NonZeroU8, где 0 — ниша. Это позволило Option<NonZero> использовать 0, чтобы представить None без использования дополнительной памяти.


На Unix-платформах File — это просто системный целочисленный файловый дескриптор. Это значит, что у нас есть возможная ниша — ведь он никогда не может быть -1! Системные вызовы, которые возвращают файловый дескриптор, используют -1 для обозначения того, что произошла ошибка (проверяется errno), так что -1 никогда не будет действительным файловым дескриптором. Начиная с Rust 1.50 эта ниша добавлена в определение типа и тоже может быть использована для оптимизации размещения значения в памяти. И следовательно Option<File> теперь имеет такой же размер, как и File!


Изменения в стандартной библиотеке


В Rust 1.50.0 были стабилизированы следующие 9 функций:



И довольно много существующих функций стало const:


  • IpAddr::is_ipv4
  • IpAddr::is_ipv6
  • Layout::size
  • Layout::align
  • Layout::from_size_align
  • pow для всех целочисленных типов
  • checked_pow для всех целочисленных типов
  • saturating_pow для всех целочисленных типов
  • wrapping_pow для всех целочисленных типов
  • next_power_of_two для всех беззнаковых целочисленных типов
  • checked_power_of_two для всех беззнаковых целочисленных типов

Смотрите подробные примечания к выпуску для более детальной информации.


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


Синтаксис, пакетный менеджер Cargo и анализатор Clippy также претерпели некоторые изменения.


Участники 1.50.0


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


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


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


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