Официальный план выпуска Rust на 2021 год

задняя часть Rust

Мы рады сообщить, что третье издание языка Rust, Rust 2021, планируется выпустить в октябре. Rust 2021 включает в себя несколько небольших изменений, но ожидайте серьезных улучшений того, как Rust работает на практике.

Что такое версия?

Релиз Rust 1.0 установлен«Стабильный без стагнации»Доставляйте ценность как ядро ​​Rust. Правило Rust, начиная с версии 1.0, заключается в том, что после того, как функция выпущена в стабильной версии, мы обязуемся поддерживать эту функцию во всех будущих выпусках.

Однако бывают случаи, когда полезно иметь возможность вносить небольшие обратно несовместимые изменения в язык. Самый очевидный пример — введение нового ключевого слова, которое сделает недействительной переменную с тем же именем. Например, первая версия Rust неasyncиawaitключевые слова. Внезапное изменение этих слов на ключевые слова в более поздней версии приведет к поломке таких вещей, какlet async = 1;.

Версияэто механизм, который мы используем для решения этой проблемы. Когда мы хотим выпустить функцию, которая иначе была бы несовместима с предыдущими версиями, мы делаем ее частью новой версии Rust. Версии можно выбирать, поэтому существующие доски не увидят эти изменения до тех пор, пока они не будут явно перенесены на новую версию. Это означает, что даже последняя версия Rust по-прежнему _не_asyncв качестве ключевого слова, если не выбрана версия 2018 или более поздняя. Этот выбор как _каждый раздел_частьCargo.toml. Зависит отcargo newНовые создаваемые доски всегда настроены на использование последней стабильной версии.

Версии не разделяют экосистему

Наиболее важным правилом управления версиями является то, что одна версия cockate может беспрепятственно взаимодействовать с другими скомпилированными версиями cockate. Это гарантирует, что решение о переходе на более новую версию является «частным решением», которое правление может принять, не затрагивая другие правления.

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

Миграция версий проста и в значительной степени автоматизирована

Наша цель — облегчить обновление кряка до более новых версий. Когда мы выпускаем новую версию, мы также предоставляеминструменты для автоматизации миграции. Он вносит необходимые небольшие изменения в ваш код, чтобы сделать его совместимым с новой версией. Например, при переходе на Rust 2018 изменилось все, что называетсяasync, чтобы использовать эквивалентсинтаксис необработанного идентификатора.r#async.

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

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

Какие изменения запланированы на Rust 2021?


За последние несколько месяцев рабочая группа Rust 2021 рассмотрела ряд предложений о том, что включить в новый релиз. Мы рады объявить окончательный список изменений версии. Каждая функция должна соответствовать двум критериям, чтобы быть включенной в этот список. Во-первых, они должны быть одобрены соответствующей командой Rust. Во-вторых, их реализация должна быть достаточно глубокой, чтобы мы были уверены, что они будут завершены к запланированным этапам.

Дополнение к прелюдии

Прелюдия к стандартной библиотекеэто модуль, который содержит все, что автоматически импортируется в каждом модуле. Он содержит часто используемые элементы, такие какOption,Vec,drop,Clone.

Компилятор Rust будет отдавать приоритет любым элементам, импортированным вручную, а не элементам из прелюдии, чтобы гарантировать, что дополнения к прелюдии не нарушат существующий код. Например, если у вас есть файл с именемexampleблок или модуль, содержащийpub struct Option;,Такuse example::*;сделаюOptionЯвно цитируя изexample; не из стандартной библиотеки.

Однако добавление трейта в прелюдию слегка ломает существующий код. еслиstd'sTryIntoтакже импортируется, затем используйтеMyTryIntoпара признаковx.try_into()Вызов может стать неоднозначным и не скомпилироваться, потому что он предоставляет метод с тем же именем. Это то, что мы не добавили в прелюдииTryIntoПричина в том, что существует много кода, который может сломаться таким образом.

В качестве решения Rust 2021 будет использовать новое вступление. Это то же самое, что и текущее введение, с тремя новыми дополнениями.

Парсер функций Cargo по умолчанию

Начиная с Rust 1.51.0, Cargo имеетновый анализатор функцийПредусмотрена поддержка выбора, которая может бытьresolver = "2"существуетCargo.toml.

Начиная с Rust 2021, это будет значение по умолчанию. То есть вCargo.tomlнаписать вedition = "2021"будет означатьresolver = "2".

Новый синтаксический анализатор функций больше не объединяет все запрошенные функции ящиков, которые зависят от нескольких способов. Подробнее см.Объявление для Rust 1.51.

IntoIterator для массивов

До Rust 1.53 были реализованы только ссылки на массивы.IntoIterator. Это означает, что вы можете&[1, 2, 3]и&mut [1, 2, 3], но не непосредственно в[1, 2, 3].

for &e in &[1, 2, 3] {} // Ok :)

for e in [1, 2, 3] {} // Error :(

Этодавняя проблема, но решение не так просто, как кажется. ТолькоДобавить реализацию трейтасломает существующий код. сегодня,array.into_iter()уже компилируется, потому что согласноКак работает синтаксис вызова метода, который неявно вызывает(&array).into_iter(). Добавление реализации черты изменит ее значение.

Обычно мы классифицируем этот тип поломки (добавление реализации функции) как «незначительный» и приемлемый. Но в этом случае кода слишком много, чтобы сломать его.

Несколько раз предлагалось: «Реализовано только для массивов в Rust 2021».IntoIterator". Однако это просто невозможно. У вас не может быть реализации трейта в одной версии, а не в другой, потому что версии могут смешиваться.

Вместо этого мы решили добавить реализации трейтов во все версии (начиная с Rust 1.53.0), но с небольшим хаком, чтобы избежать сбоев до Rust 2021. В коде Rust 2015 и 2018 компилятор по-прежнему будетarray.into_iter()решает(&array).into_iter(), как будто реализации трейта не существует. Это _только_ относится к.into_iter()Синтаксис вызова метода. Это не влияет на любой другой синтаксис, напримерfor e in [1, 2, 3],iter.zip([1, 2, 3])илиIntoIterator::into_iter([1, 2, 3]). Они начнут работать во _всех_ версиях.

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

Прерывистый захват в замыканиях

заключительное собраниеАвтоматически захватывает все, на что вы ссылаетесь, в своем теле. Например,|| a + 1автоматически фиксируетaцитаты.

В настоящее время это работает для всей структуры, даже если используется только одно поле. Например,|| a.x + 1захватить паруaцитаты, не толькоa.x. В некоторых случаях это проблема. Когда одно поле структуры было заимствовано (изменяемое) или удалено, другие поля больше нельзя использовать в замыкании, так как это захватило бы всю структуру, которая больше недоступна.

let a = SomeStruct::new();

drop(a.x); // Move out of one field of the struct

println!("{}", a.y); // Ok: Still use another field of the struct

let c = || println!("{}", a.y); // Error: Tries to capture all of `a`
c();

Начиная с Rust 2021, замыкания захватывают только те поля, которые они используют. Таким образом, приведенный выше пример отлично компилируется в Rust 2021.

Это новое поведение активно только в новых версиях, поскольку оно может изменить порядок, в котором отбрасываются поля. Что касается всех изменений версии, важно, чтобы были доступны автоматические миграции, которые будут обновлять ваши замыкания. его можно вставить внутрь крышкиlet _ = &a;, заставляя всю структуру быть захваченной, как раньше.

panic!()Согласованность макросов

panic!()Макросы — одни из самых известных макросов Rust. Тем не менее, оннекоторые тонкие сюрпризы, из-за обратной совместимости мы не можем просто изменить его.

panic!("{}", 1); // Ok, panics with the message "1"
panic!("{}"); // Ok, panics with the message "{}"

panic!()Макрос использует форматирование строки только при вызове с более чем одним аргументом. При вызове с параметром он даже не смотрит на этот параметр.

let a = "{";
println!(a); // Error: First argument must be a format string literal
panic!(a); // Ok: The panic macro doesn't care

(Он даже принимает нестроки, такие какpanic!(123), что необычно и редко полезно).

однаждыНеявные параметры форматаСтабилизируется, это будет особая проблема. Эта функция позволитprintln!("hello {name}")статьprintln!("hello {}", name)сокращение. Тем не мение,panic!("hello {name}")не будет работать, как ожидалось, потому чтоpanic!()Одиночный параметр не обрабатывается как строка формата.

Чтобы избежать этой путаницы, в Rust 2021 используется более последовательныйpanic!()макрос. новыйpanic!()Макросы больше не будут принимать произвольные выражения в качестве единственного параметра. это будет иprintln!()Опять же, всегда рассматривайте первый аргумент как строку формата. так какpanic!()Произвольные полезные нагрузки больше не будут приниматься.panic_any()был бы единственным способом запаниковать чем-то другим, кроме строки формата.

Кроме того, в Rust 2021core::panic!()иstd::panic!()будет то же самое. В настоящее время между ними существуют некоторые исторические различия при открытии или закрытии#![no_std], будут существенные отличия.

зарезервированный синтаксис

Чтобы освободить место для нового синтаксиса в будущем, мы решили сохранить синтаксис для префиксных идентификаторов и литералов:prefix#identifier,prefix"string",prefix'c', иprefix#123, вprefixМожет быть любым идентификатором. (кроме тех, которые уже имеют смысл, таких какb'…'иr"…".

Это критическое изменение, так как макросы в настоящее время принимаютhello"world", они будут рассматривать его как два отдельных токена:helloи"world". Однако (автоматическое) исправление простое. Просто вставьте пробел:hello "world".

Помимо превращения их в ошибки токенизации,RFCНи к одному из префиксов не было приложено никакого значения. Присвоение значений конкретным префиксам оставлено как предложение на будущее, и, поскольку эти префиксы пока сохранены, критических изменений не будет.

Это некоторые новые префиксы, которые вы можете увидеть в будущем.

  • f"", как сокращение для строки формата. Например,f"hello {name}", как эквивалентноformat_args!()Аббревиатура от вызова.

  • c""илиz""Представляет строку C, заканчивающуюся нулем.

  • k#keyword, чтобы разрешить запись ключевых слов, которых еще нет в текущей версии. Например, хотяasyncНе ключевое слово в 2015 году, но этот префикс позволит нам принять в 2015 годуk#asyncВместо этого, пока мы ждем выпуска 2018 года,asyncЗарезервировано как ключевое слово.

Повышение уровня двух предупреждений до серьезных ошибок

В Rust 2021 две существующие строки будут серьезными ошибками. Эти строки по-прежнему являются предупреждениями в старых версиях.

  • bare-trait-objects: В Rust 2021 используйтеdynключевые слова для идентификациитрейт-объектбудет обязательным.

  • ellipsis-inclusive-range-patterns: больше не принимается в Rust 2021устаревший..., синтаксисИспользуется в режиме инклюзивного диапазона. это было..=Вместо этого синтаксис соответствует выражениям.

Or patterns in macro_rules

Начиная с Rust 1.53.0,модельраспространяется на поддержку|, вложенные в любом месте шаблона. Это позволяет вам писатьSome(1 | 2), вместоSome(1) | Some(2). Так как раньше это просто не разрешалось, это не критическое изменение.

Однако это изменение коснулось иmacro_rulesмакрос. Этот макрос можно использовать:patРежим спецификатора фрагмента. В настоящее время,:pat_Несоответствие|, потому что до Rust 1.53 не все шаблоны (на всех уровнях вложенности) могли содержать|. принять подобноеA | Bмакросы режимов, такие какmatches!() $($_:pat)|+Поскольку мы не хотим нарушать существующие макросы, мы _имеем_ изменения в Rust 1.53.0.:patозначает включить|.

Вместо этого мы будем вносить изменения в Rust 2021. В новой версии:patСпецификатор фрагмента _будет_ соответствоватьA | B.

Поскольку иногда люди все же хотят|соответствует одному варианту шаблона, поэтому добавляет указанный фрагмент:pat_param, чтобы сохранить старое поведение. Название относится к его основному варианту использования: шаблону в объемлющем параметре.

Что дальше?

Мы планируем объединить эти изменения и полностью протестировать их к сентябрю, чтобы гарантировать, что выпуск 2021 года войдет в Rust 1.56.0.

Обратите внимание, однако, что Rust — это проект, управляемый добровольцами. Мы ставим личное благополучие всех, кто работает над Rust, в приоритете над любыми сроками и ожиданиями, которые мы можем установить. Это может означать отсрочку релиза, когда это необходимо, или отказ от функции, которая оказалась слишком сложной или напряженной для завершения вовремя.

Тем не менее, мы идем по графику, и многие сложные проблемы были решены, спасибо всем, кто внес свой вклад в Rust 2021!


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

Вскоре мы опубликуем некоторые подробности о процессе и отклоненных предложениях в блоге «Inside Rust».

Если вам действительно не терпится, многие функции уже доступны в Rust.NightlyИспользуйте `-Zunstable-options --edition=2021` на .