LINUX.ORG.RU

Rust 1.17

 ,


3

9

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

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

$ rustup update stable

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

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

Выпуск Rust 1.17.0 в основном вносит небольшие улучшения, преимущественно касающиеся удобства использования. Например, время жизни 'static теперь автоматически подразумевается для констант или статических переменных. При создании константы или статической переменной:

const NAME: &'static str = "Ferris";
static NAME: &'static str = "Ferris";

Rust 1.17 позволит вам больше не писать 'static, так как это единственное время жизни, которое имеет смысл:

const NAME: &str = "Ferris";
static NAME: &str = "Ferris";

В некоторых ситуациях это позволит избавиться от лишних повторений:

// было
const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"];

// стало
const NAMES: &[&str; 2] = &["Ferris", "Bors"];

Другим подобным косметическим улучшением является «короткая инициализация полей». Подобно ECMAScript 6, который называет это «Сокращение Значения Свойства Объектного Литерала» («Object Literal Property Value Shorthand»), дублирование может быть удалено при объявлении структур, к примеру:

// определение
struct Point {
    x: i32,
    y: i32,
}

let x = 5;
let y = 6;

// было
let p = Point {
    x: x,
    y: y,
};

// стало
let p = Point {
    x,
    y,
};

То есть форма записи x, y будет предполагать, что значения x и y соответствуют переменным с аналогичными именами, находящимися в данной области видимости.

Другое маленькое, но полезное улучшение касается в основном новичков в Rust, которые пытаются использовать +, чтобы соединить две &str вместе. Но это не работает, соединить вы можете лишь String + &str. Поэтому, было добавлено новое сообщение об ошибке, чтобы помочь пользователям, которые совершают подобную ошибку:

// код
"foo" + "bar"

// было
error[E0369]: binary operation `+` cannot be applied to type `&'static str`
 --> <anon>:2:5
  |
2 |     "foo" + "bar"
  |     ^^^^^
  |
note: an implementation of `std::ops::Add` might be missing for `&'static str`
 --> <anon>:2:5
  |
2 |     "foo" + "bar"
  |     ^^^^^

// стало
error[E0369]: binary operation `+` cannot be applied to type `&'static str`
 --> <anon>:2:5
  |
2 |     "foo" + "bar"
  |     ^^^^^
  |
  = note: `+` can't be used to concatenate two `&str` strings
help: to_owned() can be used to create an owned `String` from a string
reference. String concatenation appends the string on the right to the string on
the left and may require reallocation. This requires ownership of the string on
the left.
  |     "foo".to_owned() + "bar"

При использовании сценариев сборки Cargo вы должны указать расположение скрипта в вашем Cargo.toml. Однако, подавляющее большинство людей писали build = «build.rs», тем самым используя файл build.rs, расположенный в корне проекта. Теперь это соглашение поддерживается самим Cargo, и будет использовано по умолчанию, если существует файл build.rs. Мы предупреждали об этом изменении в течение нескольких последних выпусков. Вы также можете использовать build = false для отказа от этого соглашения.

В этом выпуске удалена старая система сборки на основе Makefile. Новая система, анонсированная в Rust 1.15, написана на Rust и в основном использует Cargo для управления сборкой. На данный момент она уже достаточно зрелая, чтобы быть единственной системой сборки.

В рамках этого изменения, пакеты из crates.io теперь можно использовать в системе сборки Rust. Первым был добавлен mdBook, и он теперь используется при сборки нашей разнообразной книжной документации:

Обратите внимание на ссылки на соответствующие репозитории; документы были перемещены из основного дерева. Кроме того, мы добавили четвертую книгу, которая все еще расположена в основном дереве: Книга «Нестабильные возможности Rust». Она описывает нестабильные возможности, содержит ссылки на задачи, связанные с их стабилизацией, и может содержать исходную документацию. Если есть возможность, которую вы хотите увидеть стабилизированной, то пожалуйста, примите участие в ее обсуждении!

Несколько выпусков назад rustup перестал по умолчанию устанавливать документацию. Мы внесли это изменение, чтобы немного разгрузить канал, а также потому, что не все пользователи в действительности хотят хранить локальную копию документации. Однако это создало ловушку: некоторые пользователи не были в курсе, что произошло изменение, и заметили бы это, только если бы у них пропало подключение к Интернету. Кроме того, некоторые пользователи хотели иметь локальную копию документации, независимо от их подключения. Таким образом, мы откатили данное изменение, и документация снова устанавливается по умолчанию.

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

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

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

  • Arc::into_raw и Rc::into_raw позволят вам забрать Arc или Rc и получить сырой указатель.
  • Arc::from_raw и Rc::from_raw позволят вам забрать сырой указатель и получить Arc или Rc.
  • Arc::ptr_eq и Rc::ptr_eq возвращает true если оба Arc или оба Rc указывают на одно и то же значение (не обязательно значения, которые сравниваются, равны).
  • Ordering::then позволит вам сцепить два Ordering вместе, и Ordering::then_with позволит сделать это с помощью функции.
  • BTreeMap::range позволит вам итерировать лишь по части BTreeMap, и BTreeMap::range_mut позволит вам сделать это с возможностью изменения. collections::Bound может дать вам еще больше контроля.
  • process::abort будет полностью завершать процесс анормальным образом.
  • ptr::read_unaligned и ptr::write_unaligned аналогичны ptr::read и ptr::write, но без требований к выравниванию.
  • Result::expect_err зеркально подобен Result::expect, то есть работает с вариантом Err, а не с вариантом Ok.
  • Cell::swap аналогичен std::mem::swap, но позволяет вам делать это с &Cell вместо &mut T.
  • Cell::replace аналогичен std::mem::replace, но позволяет вам делать это с &Cell вместо &mut T.
  • Cell::into_inner позволит вам взять Cell, и извлечь его значение.
  • Cell::take позволит вам забрать значение Cell наружу, заменив его на Default::default.

Что касается других изменений, для многих методов Cell<T> требовалось ограничение T: Copy, но теперь это требование значительно ослаблено.

Box<T> теперь реализует более дюжины новых преобразований с помощью From.

SocketAddr и IpAddr также теперь имеют несколько новых преобразований. Раньше вы должны были писать код вроде этого:

"127.0.0.1:3000".parse().unwrap()

Сейчас же вы можете писать
SocketAddr::from(([127, 0, 0, 1], 3000))
// или
([127, 0, 0, 1], 3000).into())

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

Обратная трассировка теперь имеет более приятное форматирование, опуская некоторые незначительные детали по умолчанию.

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

Помимо ранее упомянутых изменений, касающихся build.rs, у Cargo есть еще несколько новых улучшений. cargo check --all и cargo run --package — два отсутствовавших до этого момента флага, которые теперь поддерживаются.

Теперь вы можете игнорировать проверки отзыва SSL. Конечно, по умолчанию проверка все еще производится.

Новое поле в Cargo.toml, required-features, позволяет указать конкретные возможности, которые должны быть установлены для цели, которую нужно собрать. Вот пример: предположим, что мы пишем контейнер, который взаимодействует с базами данных, и хотим, чтобы он поддерживал несколько баз данных. Мы могли бы это сделать в нашем Cargo.toml:

[features]
# ...
postgres = []
sqlite = []
tools = []

Возможность tools позволяет нам включить дополнительные инструменты, а возможности postgres и sqlite указывают, какие базы данных мы хотим поддерживать.

Раньше cargo build пыталась собрать все цели, которые вам нужны. Но что, если у нас есть файл src/bin/postgres-tool.rs, который является нужным только при условии, что возможности postgres и tools были включены? Раньше нам приходилось писать что-то вроде этого:

#[cfg(not(all(feature = "postgres", feature = "tools")))]
fn main() {
    println!("This tool requires the `postgres` and `tools` features to be enabled.");
}

#[cfg(all(feature = "postgres", feature = "tools"))]
fn main() {
    // код
}

Слишком много шаблонного кода для работы с cargo build. Еще печальнее дело обстояло с examples/, которые должны демонстрировать, как использовать вашу библиотеку. Но такие махинации возможны только при работе внутри самого пакета, поэтому вы потерпите неудачу, если попытаетесь использовать пример вне этого пакета.

С помощью нового ключа required-features мы можем добавить следующее:

[[bin]]
# ...
required-features = ["postgres", "tools"]

Теперь cargo build будет собирать наш postgres-tool, только если у нас включены две эти возможности, и поэтому мы можем написать нормальный fn main без всяких нагромождений вроде cfg.

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

Много людей внесли свой вклад в создание Rust 1.17. Мы не смогли бы сделать это без всех вас. Спасибо!

Авторы перевода и публикации @kgv, @vitvakatu, @ozkriff.

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

Ответ на: комментарий от upcFrost

Разраб отдает заказчику docker image в котором уже стоят все нужные компиляторы. Как только кто-то что-то взял из дистрибутива то начинается такая параша, вроде поставьте ubuntu 12.04 в виртуалбокс иначе ничего не соберется.

pftBest ★★★ ()
Ответ на: комментарий от pftBest

Разраб отдает заказчику docker image в котором уже стоят все нужные компиляторы. Как только кто-то что-то взял из дистрибутива то начинается такая параша, вроде поставьте ubuntu 12.04 в виртуалбокс иначе ничего не соберется.

что-то я пока ансис в докере не видел. да и гимп тоже. и кстати, раз уж раст так хорошо с вендой работает - ничего что докер в юзерской семерке через тот же vbox запускается?

или ты только про компиляторы? что-то я не думаю что заказчику образ компилятора нужен

upcFrost ★★★★★ ()
Последнее исправление: upcFrost (всего исправлений: 1)
Ответ на: комментарий от upcFrost

Я не про гимп, я работаю со встраиваемыми системами где собирается прошивка. И по опыту компиляторы всегда лежат вместе с исходниками, причем часто в бинарном виде.

pftBest ★★★ ()
Ответ на: комментарий от upcFrost

или ты думаешь что нормальный админ на сервер бинарь с гитхаба качать будет?

Что-то я совсем ход мысли потерял. Попробую объяснить, что хотел сказать: не все проекты - это «бинари», которые запускают конечные пользователи. Если у нас какой-нибудь сервис, который крутится на сервере, то большая часть проблем отпадает.

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

не все проекты - это «бинари», которые запускают конечные пользователи. Если у нас какой-нибудь сервис, который крутится на сервере, то большая часть проблем отпадает.

но ведь сервис же кто-то должен запустить. и если это не in-house разработка, то запускать его будет чувак мало связанный с разрабом самого софта.

upcFrost ★★★★★ ()
Ответ на: комментарий от pftBest

Я не про гимп, я работаю со встраиваемыми системами где собирается прошивка. И по опыту компиляторы всегда лежат вместе с исходниками, причем часто в бинарном виде

ну если мы про embed, то при чем тут венда? или win embedded тоже учитываем?

upcFrost ★★★★★ ()
Ответ на: комментарий от pftBest

Я про венду ничего не говорил, я просто привел пример когда использовать компилятор из дистрибутива не рекомендуется

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

upcFrost ★★★★★ ()

Че-то не пойму, чего все так восхищаются этим растом. Вот, только что такой кусок кода попался:

loop {
        match TcpStream::connect("google.com:80") {
            Ok(_) => {
                println!("connected");
                break;
            }
            Err(e) => {
                println!("failed: {:?}", e);
            }
        }
        thread::sleep(Duration::from_secs(1));
    }
Это че, реально последнее слово в обработке ошибок? Да во всеми обсираемом го было бы и то короче:
for {
	err := TcpStream.connect("google.com:80") //хз, что это, оставляю как есть
	if err == nil {
                fmt.Println("connected")
		break
        }
	fmt.Println("failed: ", err)
	time.Sleep(1 * time.Second)
}

anonymous ()
Ответ на: комментарий от anonymous

Код семантически разный. В Go тебе ничто не мешает использовать результат, возвращаемый TcpStream::connect, без проверки ошибки и получить NPE.

Вообще странный пример: зачем коннектиться по TCP и не иcпользовать соединение?

mersinvald ★★★ ()
Ответ на: комментарий от anonymous

Ну и тут пример конкретно обработки ошибок, причем обоих вариантов. Вот эквивалентный твоему го-коду пример на Rust:

loop {
    if let Ok(_) = TcpStream::connect("google.com:80") {
        println!("connected");
        break;
    }
    println!("failed: {:?}", e);
    thread::sleep(Duration::from_secs(1));
}

В отличии от Go чтобы передать ошибку выше, а не обрабатывать на месте, есть оператор и не надо писеть if err == nil

mersinvald ★★★ ()
Последнее исправление: mersinvald (всего исправлений: 1)
Ответ на: комментарий от mersinvald

В Go тебе ничто не мешает использовать результат, возвращаемый TcpStream::connect

А тебе ничто не мешает забыть уходя закрыть дверь дома, и вернуться в пустую квартиру. Теоретики, блин. А ты попробуй написать пару тысяч строк кода на го и не выработать автоматическую привычку к написанию кода обработки ошибки. Код отсюда:https://thesquareplanet.com/blog/the-story-of-a-rust-bug/

anonymous ()
Ответ на: комментарий от anonymous

Вопросы к личному вкусу автора, а не к синтаксису языка. Повторюсь: хочешь сравнивать — сравнивай семантически одинаковые примеры, как тот что я написал, например.

mersinvald ★★★ ()
Ответ на: комментарий от anonymous

Суть растовской обработки ошибок в том, что можно написать так:

    loop {
        TcpStream::connect("google.com:80")?;
        thread::sleep(Duration::from_secs(1));
    }

Просто данный пример неудачный.

RazrFalcon ★★ ()
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от anonymous

Да, тут косяк, действительно, не заметил. Если переписать код из статьи грамотно, то получится вот так:

while let Err(e) = TcpStream::connect("google.com:80") {
    println!("failed: {}", e);
    thread::sleep(Duration::from_secs(1));
}
println!("connected");

mersinvald ★★★ ()
Ответ на: комментарий от anonymous

Зачем ты съехал на сишку, а?

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

Если ошибку возможно допустить, ее допустят, не важно сколько строк кода в день пишет человек

mersinvald ★★★ ()
Ответ на: комментарий от anonymous

Вот, только что такой кусок кода попался:

Этот кусок кода имеет мало общего с реальным кодом на Rust.

use std::io;
use std::io::prelude::*;
use std::net::TcpStream;

fn print_http(host: &str, port: u16) -> io::Result<()>
{
    let mut stream = TcpStream::connect((host, port))?;
    println!("connected");

    let header = format!("GET / HTTP/1.0\nHost: {}\n\n", host);
    stream.write_all(header.as_bytes())?;

    let mut buffer = String::new();
    let bytes = stream.read_to_string(&mut buffer)?;
    println!("{} bytes", bytes);
    println!("{}", buffer);

    Ok(())
}

fn try_print_http(host: &str, port: u16)
{
    while let Err(err) = print_http(host, port) {
        println!("error: {:?}", err);
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

fn main() {
    try_print_http("www.google.com", 80);
}
anonymous ()
Ответ на: комментарий от mersinvald

АНБ
программа по взлому популярных ОС
не, не слышал.

Тут, кстати недавно червь ~пи@*#~ вымогатель пролез через дыру в самбе заразил тысячи компов под офтопом.

А написан он был на основе программы, которая утекла на викиликс из АНБ...

И да, в линуксовой самбе нашли почти такую же уязвимость...

КИСЕЛЕФ.ЖЭПЭГЕ

anonymous ()