Команда Rust рада представить выпуск Rust 1.16.0. Rust — это системный язык программирования, нацеленный на безопасность, скорость и параллельное выполнение кода.


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


$ rustup update stable

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


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


Самым большим дополнением в Rust 1.16 является команда cargo check. Эта новая подкоманда в большинстве случаев должна ускорить процесс разработки.


Что она делает? Давайте вернёмся немного назад и поговорим о том, как rustc компилирует ваш код. Компиляция происходит в несколько "проходов". Это значит, что компилятор выполняет множество различных этапов, прежде чем из вашего исходного кода будет создан бинарный файл. Вы можете увидеть каждый их этих этапов (и сколько времени и памяти они занимают) передав компилятору параметр -Z time-passes (только для nightly):



rustc .\hello.rs -Z time-passes
time: 0.003; rss: 16MB  parsing
time: 0.000; rss: 16MB  recursion limit
time: 0.000; rss: 16MB  crate injection
time: 0.000; rss: 16MB  plugin loading
time: 0.000; rss: 16MB  plugin registration
time: 0.049; rss: 34MB  expansion
<snip>

Их много. Однако вы можете разделить их на два больших этапа. Первый: rustc выполняет все проверки безопасности и корректности синтаксиса. Второй: после того как он убедится, что всё в порядке, он создаст бинарный файл, который вы в конечном итоге запустите.


Как видите, второй этап занимает много времени. И в большинстве случаев в нём нет необходимости. Многие разработчики работают над проектами на Rust примерно так:


  1. Написать немного кода.
  2. Запустить cargo build, чтобы убедиться, что он компилируется.
  3. Повторить первые два шага при необходимости.
  4. Запустить cargo test, чтобы убедиться, что тесты успешно выполняются.
  5. Перейти к первому шагу.

На втором шаге вы никогда не запускаете ваш код. Вы заинтересованы только в сообщениях от компилятора. cargo check решает именно эту задачу: он запускает все проверки компилятора, но не создаёт бинарный файл.


Так какое же ускорение вы на самом деле получите? Как и для большинства вопросов, касающихся производительности, ответ — "когда как". Вот некоторые очень ненаучные тесты:


первоначальная сборка первоначальная проверка ускорение повторная сборка повторная проверка ускорение
thanks 134.75s 50.88s 2.648 15.97s 2.9s 5.506
cargo 236.78s 148.52s 1.594 64.34s 9.29s 6.925
diesel 15.27s 12.81s 0.015 13.54s 12.3s 1.100

Категория 'первоначальная' — это первая сборка после клонирования проекта. Для категории 'повторная' добавлялась одна пустая линия в начало файла src\lib.rs, после чего команда выполнялась повторно. Вот почему первоначальная сборка выглядит более печально; помимо самого проекта команда выполняется для всех его зависимостей. Как видите, большой проект с большим количеством зависимостей увидит заметные улучшения, но для маленьких почти нет разницы.


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


Другие улучшения


Для поддержки cargo check, rustc научился генерировать новый вид файлов: .rmeta. Этот файл содержит только метаданные об определённом контейнере. cargo check использует это для ваших зависимостей, чтобы компилятор мог проверить типы и тому подобное. Это также полезно для Rust Language Server и, возможно, других инструментов, которые появятся позже.


Другое важное изменение — удаление давней диагностики: consider using an explicit lifetime parameter. Эта диагностика срабатывала всякий раз, когда у вас неверная аннотация времени жизни, и компилятор думает, что вы имели ввиду что-то другое. Рассмотрим следующий код:


use std::str::FromStr;

pub struct Name<'a> {
    name: &'a str,
}

impl<'a> FromStr for Name<'a> {
    type Err = ();

    fn from_str(s: &str) -> Result<Name, ()> {
        Ok(Name { name: s })
    }
}

Здесь Rust не уверен, что делать с временем жизни; этот код не гарантирует, что s будет жить столько же, сколько и Name. При этом s необходим для того чтобы Name был действительным. Давайте попробуем скомпилировать этот код в Rust 1.15.1:


> rustc +1.15.1 foo.rs --crate-type=lib
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
  --> .\foo.rs:10:5
   |
10 |       fn from_str(s: &str) -> Result<Name, ()> {
   |  _____^ starting here...
11 | |         Ok(Name { name: s })
12 | |     }
   | |_____^ ...ending here
   |
help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name, ()>
  --> .\foo.rs:10:5
   |
10 |       fn from_str(s: &str) -> Result<Name, ()> {
   |  _____^ starting here...
11 | |         Ok(Name { name: s })
12 | |     }
   | |_____^ ...ending here

Компилятор объясняет проблему и даёт полезный совет. Что же, давайте попробуем им воспользоваться. Изменим код, добавив в него 'a, и попробуем скомпилировать снова.


> rustc +1.15.1 .\foo.rs --crate-type=lib
error[E0308]: method not compatible with trait
  --> .\foo.rs:10:5
   |
10 |       fn from_str(s: &'a str) -> Result<Name, ()> {
   |  _____^ starting here...
11 | |         Ok(Name { name: s })
12 | |     }
   | |_____^ ...ending here: lifetime mismatch
   |
<snip>
help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name<'a>, ()>
  --> .\foo.rs:10:5
   |
10 |       fn from_str(s: &'a str) -> Result<Name, ()> {
   |  _____^ starting here...
11 | |         Ok(Name { name: s })
12 | |     }
   | |_____^ ...ending here

Он всё ещё не работает. Совет был не такой уж и полезный. Теперь он предлагает добавить ещё одно время жизни, на этот раз для Name. Если мы сделаем это...


> rustc +1.15.1 .\foo.rs --crate-type=lib
<snip>
help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Name<'a>, ()>
  --> .\foo.rs:10:5

… это кино я уже смотрел… Компилятор?!


У этой диагностики были благие намерения, но, как видно из этого примера, когда она ошибалась, она ошибалась очень сильно. Иногда она даже предлагала некорректный для Rust синтаксис! Более того, более опытные программисты на Rust на самом деле не нуждаются в этой подсказке, но начинающие принимали их на веру, и уходили в дебри. Из-за этого мы решили полностью удалить это сообщение. Возможно мы вернём его в будущем, но только если мы сможем ограничить ложные срабатывания.


Из других диагностических изменений, предыдущая версия Rust пыталась предложить исправления для опечаток:


let foo = 5;

println!("{}", ffo);

Код выше вызывал следующую ошибку:


error[E0425]: cannot find value `ffo` in this scope
 --> foo.rs:4:20
  |
4 |     println!("{}", ffo);
  |                    ^^^ did you mean `foo`?

Однако это могло произойти только в определённых обстоятельствах: иногда для локальных переменных и для полей структур. Теперь это работает почти везде. В сочетании с некоторыми другими соответствующими улучшениями это приводит к значительному улучшению этих видов диагностики.


Подробнее смотрите примечания к выпуску.


Стабилизация библиотек


Был стабилизирован 21 новый интерфейс:



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


Теперь все структуры в стандартной библиотеке реализуют Debug.


Улучшено сообщение об ошибке при получении среза &str. Например, для этого кода:


&"abc???"[..4]

будет выведена следующая ошибка:


thread 'str::test_slice_fail_boundary_1' panicked at 'byte index 4 is not
a char boundary; it is inside '?' (bytes 3..5) of `abc???`'

Части после ; раньше не было.


Подробнее смотрите примечания к выпуску.


Возможности Cargo


В дополнении к cargo check, у Cargo и crates.io появилось несколько новых возможностей. Например, cargo build и cargo doc теперь принимают флаг --all для сборки и документировании всех контейнеров в вашем рабочем пространстве.


У Cargo теперь есть флаг --version --verbose, на подобии rustc.


Crates.io теперь может отображать значки TravisCI или AppVeyor для вашего контейнера.


И Cargo и crates.io теперь понимают категории. В отличие от ключевых слов, которые могут быть указаны в свободной форме, категории курируются. Ключевые слова, в отличии от категорий, используются для поиска. Другими словами, категории предназначены для помощи в просмотре каталога, а ключевые слова предназначены для поиска.


Вы можете просматривать контейнеры по категориям здесь.


Подробнее смотрите примечания к выпуску.


Разработчики версии 1.16.0


В последнем выпуске мы представили thanks.rust-lang.org. Мы занимаемся некоторым рефакторингом, чтобы помимо самого Rust добавить и другие проекты. Мы надеемся представить это в следующем выпуске.


137 человек внесли свой вклад в Rust 1.16. Спасибо!


Автор перевода: Сергей Веселков

Поделиться с друзьями
-->

Комментарии (12)


  1. ozkriff
    21.03.2017 13:11
    +9

    Раз никто не рвется комментировать, скажу что мой проект пошаговой игры на ржавчине еще не помер, хоть времени на него не получается много выделять:


    https://users.rust-lang.org/t/this-month-in-zone-of-control/6993/2


    И вот новый встроенный cargo check чертовски полезен, потому что ZoC разбит на несколько пакетов и прошлые итерации cargo check помогали только при работе над пакетом самого верхнего уровня.


    Это, конечно, не полноценное решение долгих времен сборки, но на практике все же помогает сильно — ожидание уменьшается с пары десятков до просто пары секунд.


    1. Halt
      21.03.2017 14:22
      +5

      Не комментируют, наверное потому, что релиз проходной. Конечно, cargo check это важно и полезно, но не настолько круто, как custom derive :) Вот когда инкрементальную компиляцию включат по умолчанию будет интересно (хотя у меня и так вроде работает нормально).

      P.S.: Еще неплохо было бы написать про возможность использования Self в реализациях и в структурах.


    1. snuk182
      21.03.2017 15:07
      +2

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


    1. Gexon
      21.03.2017 22:13
      +2

      Использую только ночники, но узнал о карго чек из этой статьи, спасибо!)


  1. Beholder
    21.03.2017 15:02
    +3

    Очень хотелось бы дождаться кроссплатформенной GUI-библиотеки, чтобы писать под десктоп. Боюсь, что дождаться не получится, и придётся писать что-то своё. :)
    Я знаю про биндинг к GTK, например, но он сильно монстрообразный по части сборки и настройки, и кроссплатформенность его под вопросом.


    1. snuk182
      21.03.2017 15:09
      +3

      libui + биндинг. На винде, правда, собирается только с msvc.


      1. Beholder
        21.03.2017 17:41

        Опять биндинг, опять сложности со сборкой…
        Была мысль взять исходники SWT и просто передрать всё с Java на Rust, используя для зависимостей только библиотеки вызова ОС (например winapi).


        1. snuk182
          21.03.2017 18:57
          +3

          просто передрать всё с Java на Rust

          С учетом особенностей модели памяти и самого языка Rust — у вас уйдет на это примерно полторы вечности. Уж проще поковырять и попатчить оригинал libui, чтоб собирался стабильно. Это если вам важен нативный look and feel. Если нет — берите Conrod.


    1. ozkriff
      21.03.2017 18:02
      +1

      да, в https://github.com/kud1ing/awesome-rust/#gui пока в основном привязки к сишным и плюсовым библиотекам :(


      Если вдруг еще не натыкался и немедленный режим не пугает, то можно Conrod попробовать:



    1. AlexCoffee
      21.03.2017 20:20
      +2

      Недавно на хабре была статья про библиотеку nuklear. Вот биндинг для rust.
      Только в версии для раста еще нет бекенда для GDI+, но скоро должен появиться.


      1. snuk182
        23.03.2017 18:37
        +2

        но скоро должен появиться

        Мне бы ваш оптимизм… Тут такую виндо-специфическую портянку портировать надо. Надеюсь в отпуске взяться (он уже скоро).