Автоматическое управление памятью в Rust избавляет разработчика от ошибок при манипулировании указателями и защищает от проблем, возникающих из-за низкоуровневой работы с памятью, таких как обращение к области памяти после её освобождения, разыменование нулевых указателей, выход за границы буфера и т.п. Для распространения библиотек, обеспечения сборки и управления зависимостями проектом развивается пакетный менеджер Cargo. Для размещения библиотек поддерживается репозиторий crates.io.
Основные новшества:
- Продолжена работа по стабилизации константных дженериков («const generics«), которые теперь могут применяться для индексации массивов не только через оператор «[]», но и при помощи типажей ops::Index и IndexMut (добавлены реализации 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); // slices worked before assert_eq!(second(&array), &2); // now it also works directly }
- Стабилизировано применение любых const-значений при определении массивов с использованием синтаксиса «[x; N]». Ранее при числе повторов «N» больше единицы const-выражения в значении «x» разрешалось использовать только для реализация типажа Copy. Теперь это ограничение снято.
fn main() { const NONE: Option‹Vec‹i32›› = None; const EMPTY: Option‹Vec‹i32›› = Some(Vec::new()); let nones = [NONE; 10]; let empties = [EMPTY; 10]; }
- Разрешено безопасное назначение полей ManuallyDrop‹T› в объединениях (union). Ранее, в режиме safe могли использоваться только типажи Copy, так как имеется неопределённость по поводу того, какой вариант остаётся действительным после применения Drop. ManuallyDrop‹T› не требует Drop, поэтому назначение данных полей можно считать безопасным.
- Для типа File на Unix-системах реализована поддержка нишевого значения (niche) «-1», которое кодирует ошибку при работе с файловым дескриптором. Под нишевым значением подразумевается особое значение, которое может влиять на оптимизацию размещения типа в памяти, но является недопустимым для типа (например, нишевым является значение 0 для типов NonZero). Структура File в окружениях Unix определяет файловый дескриптор, который не может быть отрицательным, но, при этом системные вызовы могут возвращать в дескрипторе значения «-1», сигнализирующие об ошибке операции. Добавление нишевого значения позволило сделать размер Option‹File› идентичным размеру File.
- В разряд стабильных переведена новая порция API, в том числе стабилизированы методы:
bool::then
btree_map::Entry::or_insert_with_key
f32::clamp
f64::clamp
hash_map::Entry::or_insert_with_key
Ord::clamp
RefCell::take
slice::fill
UnsafeCell::get_mut
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
для всех беззнаковых целых типов.Дополнительно можно отметить результаты сравнения производительности переключения контекста и потребления памяти при использовании потоков Rust async и потоков, предоставляемых ядром Linux. Время переключение контекста между async-задачами составило 0.2µs, а переключение контекста между потоками ядра в Linux — 1.7µs, но разница исчезает если переключение контекста вызвано готовностью ввода/вывода и в обоих случаях приближается к 1.7µs. Преимущества async также пропадают в случае привязки потока к одному ядру CPU. ~300ns
Время создания новой задачи составляет для async ~300ns, а для Linux-потоков — ~17µs. На обычном ноутбуке с 4-ядерным CPU и 32 ГБ ОЗУ не возникло проблем с созданием 150 тысяч async-задач, но удалось запустить только 80 тысяч Linux-потоков. Минимальное потребление памяти на задачу составило нескольких сотен байт для async и 20КБ (9.5КБ в пространстве пользователя + 10КБ в ядре) для Linux-потоков.
Источник: http://www.opennet.ru/opennews/art.shtml?num=54575