Команда 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" (репозиторий)
- Книга "Справка по Rust" (репозиторий)
- Книга "Растономикон" (репозиторий)
Обратите внимание на ссылки на соответствующие репозитории; документы были перемещены из основного дерева. Кроме того, мы добавили четвертую книгу, которая все еще расположена в основном дереве: Книга "Нестабильные возможности Rust". Она описывает нестабильные возможности, содержит ссылки на задачи, связанные с их стабилизацией, и может содержать исходную документацию. Если есть возможность, которую вы хотите увидеть стабилизированной, то пожалуйста, примите участие в ее обсуждении!
Несколько выпусков назад rustup
перестал по умолчанию устанавливать документацию. Мы внесли это изменение, чтобы немного разгрузить канал, а также потому, что не все пользователи в действительности хотят хранить локальную копию документации. Однако это создало ловушку: некоторые пользователи не были в курсе, что произошло изменение, и заметили бы это, только если бы у них пропало подключение к Интернету. Кроме того, некоторые пользователи хотели иметь локальную копию документации, независимо от их подключения. Таким образом, мы откатили данное изменение, и документация снова устанавливается по умолчанию.
Наконец, хотя этот выпуск и полон улучшений, но есть один маленький шажок назад, о котором мы хотим сообщить вам с сожалением. В Windows была выпущена Visual Studio 2017, и Microsoft изменила структуру установки программного обеспечения. Rust не может автоматически определить её местоположение, и хотя мы работали над необходимыми изменениями, но не успели к этому выпуску. До тех пор, Visual Studio 2015 все еще работает нормально, или же вы можете запустить vcvars.bat
в командной строке. Мы надеемся, что эта работа будет выполнена в кратчайшие сроки.
Подробнее смотрите примечания к выпуску.
Стабилизация библиотек
Был стабилизирован 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())
Что позволит удалить ненужный парсинг во время выполнения. Оба варианта примерно одинаково удобно читаются, все зависит от ваших предпочтений.
Обратная трассировка теперь имеет более приятное форматирование, опуская некоторые незначительные детали по умолчанию. Например, полная обратная трассировка:
thread 'main' panicked at 'explicit panic', foo.rs:2
stack backtrace:
1: 0x55c39a23372c - std::sys::imp::backtrace::tracing::imp::write::hf33ae72d0baa11ed
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:42
2: 0x55c39a23571e - std::panicking::default_hook::{{closure}}::h59672b733cc6a455
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:351
3: 0x55c39a235324 - std::panicking::default_hook::h1670459d2f3f8843
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:367
4: 0x55c39a235afb - std::panicking::rust_panic_with_hook::hcf0ddb069e7beee7
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:555
5: 0x55c39a22e866 - std::panicking::begin_panic::heb433e9aa28a7408
6: 0x55c39a22e9bf - foo::main::hd216d4a160fcce19
7: 0x55c39a23d44a - __rust_maybe_catch_panic
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libpanic_unwind/lib.rs:98
8: 0x55c39a236006 - std::rt::lang_start::hd7c880a37a646e81
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panicking.rs:436
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/panic.rs:361
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libstd/rt.rs:57
9: 0x55c39a22e9e9 - main
10: 0x7f5e5ed3382f - __libc_start_main
11: 0x55c39a22e6b8 - _start
12: 0x0 - <unknown>
теперь имеет вид
thread 'main' panicked at 'explicit panic', foo.rs:2
stack backtrace:
0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
at /checkout/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
1: std::sys_common::backtrace::_print
at /checkout/src/libstd/sys_common/backtrace.rs:71
2: std::panicking::default_hook::{{closure}}
at /checkout/src/libstd/sys_common/backtrace.rs:60
at /checkout/src/libstd/panicking.rs:355
3: std::panicking::default_hook
at /checkout/src/libstd/panicking.rs:371
4: std::panicking::rust_panic_with_hook
at /checkout/src/libstd/panicking.rs:549
5: std::panicking::begin_panic
6: foo::main
7: __rust_maybe_catch_panic
at /checkout/src/libpanic_unwind/lib.rs:98
8: std::rt::lang_start
at /checkout/src/libstd/panicking.rs:433
at /checkout/src/libstd/panic.rs:361
at /checkout/src/libstd/rt.rs:57
9: main
10: __libc_start_main
11: _start
по умолчанию. Вы можете установить переменную окружения RUST_BACKTRACE = full
, чтобы получить полную обратную трассировку. В будущем мы планируем убрать еще больше лишней информации; См. эту ошибку.
Подробнее смотрите примечания к выпуску.
Возможности 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 за помощь при переводе.
Если вы заинтересовались Rust и у вас есть вопросы, присоединяйтесь!
Комментарии (46)
rkuvaldin
02.05.2017 11:23На нем вообще много сейчас пишут?
Ockonal
02.05.2017 12:31+1Пытаюсь сейчас зайти на него после с++. Необычно, но нравится.
Кстати есть вопрос. Допустим у меня происходит парсинг html-кода, который должен вернуть какое-то число.
fn parse_page_count(document : kuchiki::NodeRef) -> i32 { let parent = document.select(".bottom_info #pagination p").unwrap().nth(0).unwrap(); let firstBold = parent.as_node().select("b").unwrap().nth(1).unwrap(); let result = firstBold.as_node().as_text().unwrap().borrow().parse::<i32>(); match result { Err(_) => panic!("Failed to parse page count"), Ok(pagesCount) => pagesCount } }
Как вообще правильно и принято в Rust оборачивать все это в проверкии и возвращение ошибки? Как использовать оператор "?" вместо кучи unwrap? Какой возвращаемый тип должен быть у функции (понимаю, что Result, но как объединить для всего).
Еще местами не понятны, когда в цепочке вызовов как выше компилятор бросается ошибкой, что переменная уже borrowed, поэтому приходится создавать временную переменную и использовать ее дальше в цепочке. Неясно почему компилятор сам не может этого сделать/понять. В общем после обычных языков первое время очень долго думаешь :)snuk182
02.05.2017 12:41+3Как вообще правильно и принято в Rust оборачивать все это в проверкии и возвращение ошибки?
С помощью Result.
Описание самого принципа обработки ошибок (тут требуется поправка — вместо макроса try! используется сахар ?, принцип действия точно такой же)Ockonal
02.05.2017 12:46Это поможет, если оборачиваемые методы возвращают одну и ту же сигнатуру Result, оно потом пробрасывается вверх. А в случае как на моем примере, там тип Err отличается.
Halt
02.05.2017 13:00+1Посмотрите на фрагмент, приведенный ниже или на полный вариант в окрестности строки 152.
impl ServerState { pub fn parse(&mut self, message: &str) -> Result<(), &'static str> { for (k, v) in parse_table(&message) { match k { "frame" => self.frame = Rc::new(Frame::parse_from(v)?), "deaths" => self.deaths = v[1 .. v.len()-1] // strip quotes .split(',') .filter(|e| e.len() > 0) // a,,b .map(|x| x.parse().map_err(|_| "parse error")) .collect::<Result<_,_>>()?, // TODO _ => unimplemented!() } } Ok(()) } // ... }
Из функции я выбрасываю колхозную ошибку&'static str
, ибо лень и прототип. Фукнции парсинга возвращают нормальные ошибки, которые надо привести к строке.
Самое интересное происходит в обработке «deaths»: с помощью функциональной магии и трансформации монад мы преобразуем Collection<Result<T, E>> в Result<Collection, E>>, который потом разворачиваем с помощью ?.
Halt
02.05.2017 12:46+3Если опустить детали реализации, то `?` просто выбрасывает ошибку из функции. Нормальное же значение «проглатывается» на текущем лексическом уровне. Подробнее можно посмотреть в документации.
Если у вас есть операция, которая возвращает к примеру io::Result, а ваша функция определяет свой тип ошибки, то к вашим услугам метод map_err().
snuk182
02.05.2017 12:52+6Пример из жизни:
fn create_player(player: &Player, tattva: Alb<Tattva>, storage: Al<Storage<Player, PlayerParams>>, idf: Al<IdFactory>) -> Result<Player, PlayerInitializeError> { let universe = get_universe(player.uid)?; // <- get_universe возвращает Result<Universe, PlayerInitializeError>. Если она вернула error, create_player тоже его возвращает тут же. Похоже на проброс исключения в Java. let mut player = player.clone(); player.id = idf.write().unwrap().player(); let params = PlayerParams { universe: universe.name.clone(), lookup: PlayerParamsLookup::Id(player.id), }; storage.write().unwrap().save(&player, ¶ms).map_err(|e| { error!("[{}] Error saving player {} '{}': {}", SCENE_NAME, player.id, player.name, e); PlayerInitializeError::CannotSave })?; // save возвращает Result<(), StorageError>. StorageError нельзя вернуть вместо PlayerInitializeError, поэтому мы его преобразовываем с помощью map_err, а заодно и логгируем. Можно враппер написать, но обычно незачем, если все логгируется. Ok(player) }
Ockonal
02.05.2017 13:03+1Спасибо, а вопрос по поводу цепочки вызовов?
Вот пока не совсем понимаю где можно использовать clone, где вот эти into. Даже в вашем примере, насколько правильно создавать копию игрока.
А так крутой язык, всем советую попробовать. Сначала казался бесполезным и не стоящим своего изучения.
Но вот если разработчики еще собираются работать над упрощением порога входа, то должно быть вообще круто.
Им бы еще поработать в направлении веба, чтобы было удобно писать бекенд. Понимаю, что это не ниша языка изначально, но сейчас, например, переписываю для своего сайта с аудиокнигами парсеры на Rust, все это мультипоточно в виде демона, было бы удобно использовать одни и те же структуры парсеров и бекенда сайта.snuk182
02.05.2017 13:09+3Ockonal
02.05.2017 13:13+1Мне скоро нужно будет заняться одним очень масштабным мероприятием, где буду реализовывать систему электронных денег, оплаты, входа и и т.д. Хочу попробовать сделать бекенд на расте. Вот здесь его стабильность и строгая типизация может очень помочь от глупых ошибок. На librocket и смотрел :)
Ockonal
02.05.2017 13:18По поводу первого вопроса чуть разверну:
let parent = document.select(".bottom_info #pagination p").unwrap().nth(0).unwrap(); let firstBold = parent.as_node().select("b").unwrap().nth(1).unwrap(); let result = firstBold.as_node().as_text().unwrap().borrow().parse::<i32>();
Почему код выше работает, а если объединить в одну строчку:
let firstBold = parent.as_node().select("b").unwrap().nth(1).unwrap().as_node().as_text().unwrap().borrow().parse::<i32>();
То матерится вот такSirikid
02.05.2017 13:47+4Возвращенное из функции значение умирает в конце выражения, чтобы продлить время жизни надо сохранить значение в переменную (она тоже умрет в конце блока, но тогда все необходимые операции будут уже завершены).
splav_asv
02.05.2017 14:00Предположу, что первая строка создает некий объект, а в процессе получения result его часть заимствуют. Таким образом в первом случае result корректен до того момента, пока parent не выйдет из области видимости. Для однострочника parent создается только как временный и разрушается по окончании данной строки. Получается не у кого заимствовать.
Формально rust прав. Если временный объект не доживает до конца области видимости, можно получить подвисший указатель и долго искать в чем плавающий баг.Ockonal
02.05.2017 14:06Формально прав, а практически этот объект не умрет сам по себе, верно?
Получается, без знания сигнатур функций и их возвращаемых значений нереально писать код, который будет компилироваться с первого раза.splav_asv
02.05.2017 14:09Компилятор может освободить память на стеке и использовать для следующего объекта. Да, в общем случае нельзя. Отчасти поэтому отказались от автоматического вывода сигнатур.
splav_asv
02.05.2017 14:12+3P.S. cargo check иногда сильно экономит время, если еще не пользуетесь.
Ockonal
02.05.2017 14:14+1Да, спасибо, стоит уже на хоткее билда :)
В общем случае понятно. Раст заставляет вас пострадать, при написании кода, зато в результате получаем гарантию, что не придется дебажить потом непонятные вылеты и проблемы с памятью.BlessMaster
02.05.2017 23:34+3Да, и
чем дальше в лес,чем крупнее проект, тем это качество всё важнее.
При этом попутно происходит ещё и обучение — почему так или иначе делать нельзя или просто плохо в других языках, у которых нет такого строгого контроля.
А с опытом эта «борьба» с компилятором проходит, начинаешь чётко представлять как всё будет работать, и эти ошибки из-за непонимания перестают отнимать время.
Кстати, очень рекомендовал бы сразу изучить вдоль и впоперек стандартную библиотеку — она минималистична и это не отнимет много времени, зато многие "тупиковые" вопросы, когда непонятно что делать, будут сняты.
googol
10.05.2017 05:33+2Блогпост по теме объясняющий проблему http://manishearth.github.io/blog/2017/04/13/prolonging-temporaries-in-rust/
splav_asv
10.05.2017 10:18+1По ссылке есть малоизвестная интересная фича, по крайней мере я не знал.
let owned; //
let maybe_foo = if some_condition {
thing.get_ref()
} else {
owned = thing.get_owned();
owned.as_ref()
};
googol
10.05.2017 17:27+1Блог http://manishearth.github.io/blog/ в целом очень информативен. Крайне рекомендую к прочтению вот эти статьи
http://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/
http://manishearth.github.io/blog/2015/05/27/wrapper-types-in-rust-choosing-your-guarantees/
http://manishearth.github.io/blog/2015/05/30/how-rust-achieves-thread-safety/
http://manishearth.github.io/blog/2017/04/13/prolonging-temporaries-in-rust/
http://manishearth.github.io/blog/2017/01/10/rust-tidbits-box-is-special/
c0va23
03.05.2017 01:31Но rocket пока работает только на ночных сборках. В продакшен такое пускать не очень хочется. Хотя выглядит он очень вкусно.
Arekusei
04.05.2017 14:12А что именно Rocket требует из ночных сборок?
Если я правильно понял то он нуждается в плагинах для кодогенерации, да?
А вообще есть какие-то планы у Rust по стабилизации данных фич?ozkriff
04.05.2017 14:14+1https://github.com/SergioBenitez/Rocket/blob/30fac3297/lib/src/lib.rs#L1-L10
довольно много всего:
#![feature(specialization)] #![feature(conservative_impl_trait)] #![feature(drop_types_in_const)] #![feature(associated_consts)] #![feature(const_fn)] #![feature(type_ascription)] #![feature(lookup_host)] #![feature(plugin)] #![feature(never_type)] #![feature(concat_idents)]
snuk182
02.05.2017 13:48+3Clone — это клонирование. Явная копия объекта (неявная — это Copy, но от Copy на практике больше мороки, чем пользы). Может быть не так тривиальна, если клонируемый тип имеет поля-ссылки.
Into/From — паттерн Adapter из ООП, преобразует одни типы в другие, заодно является полу-сахаром для компилятора, если надо использовать (вернуть из функции, передать в функцию) объект, несовместимый с сигнатурой, но зато имеющий реализацию Into или From. Но тоже явно, методы из типажей надо вызывать вручную.splav_asv
02.05.2017 14:06+1Но да, для From и Into явное, прошу прощения, слегка невнимательно прочитал.
BlessMaster
02.05.2017 23:38На самом деле уточню, что для ошибок в случае
try!
/?
— вызов .into() происходит «под капотом», что сильно упрощает жизнь, да и в целом, макросы немного нивелируют принцип явности.
Halt
04.05.2017 13:39+4Добавлю еще немного про обработку ошибок. В книге хорошо описано, как правильно работать с ошибками. Там разобраны все типичные ситуации: как создавать собственный тип ошибок, как пробрасывать ошибки наверх и т.д.
При чтении можно мысленно заменять try!() на ?, смысл будет тот же.Ockonal
04.05.2017 13:40Спасибо, я уже наловчился со всеми мапперами ошибок. Главное найти грань, чтобы из трех строк кода не полчилось 30 :)
Halt
04.05.2017 13:42+2Так там наоборот из 30 получится 3. Реализация трейтов преобразования поможет автоматически захватывать ошибки разных типов вообще без map_err(). Просто пишете ?, а оно само разберется.
pftbest
02.05.2017 22:02+2Не обязательно делать map_err, оператор? умеет автоматически конвертировать типы ошибок если для них определен трейт From.
GraD_Kh
10.05.2017 21:46+1Начал разбираться с растом, и удивился и порадовался его продуманности во многих вещах — контроль времени жизни ссылок, невозможность использовать после move, функциональные возможности. Но очень расстраивает отсутствие корутин и N:M-параллелизма. Даже аналога обычного C++-ного std::async нет из коробки, да и futures какие-то странные. Мне кажется, что если бы это было, то rust мог бы серьезно побороться за нишу серверныз приложений, а пока шансов, увы, немного.
Насколько я понял, была годная реализация корутин, но она оказалась несовместимой со стандартной библиотекой из-за того, что последняя активно использует TLS. И на данный момент корутины в принципе не в приоритете. Было бы хорошо, если бы кто-то внес уточнения, вдруг я что-то упустил.TargetSan
10.05.2017 22:55+2Для начала, std::async из с++ это просто потоковая функция с гардом, на котором можно подождать окончания и получить результат. Полный аналог https://doc.rust-lang.org/std/thread/fn.spawn.html. Если хотите полноценной асинхронности — https://tokio.rs/
GraD_Kh
11.05.2017 09:47Я в курсе, что такое std::async. И если быть точным, то она не всегда создает новый поток. Во-первых в зависимости от дефолтной политики результат может быть получен вообще синхронно. Во-вторых, в зависимости от имплементации асинхронная версия может либо создавать новый поток, либо использовать пул потоков.
За наводку на https://tokio.rs/ — спасибо.TargetSan
11.05.2017 11:01+1Вот в этом и проблема, что смешали в кучу 2 разных инструмента, добавив столь любимую Комитетом горстку implementation-defined. Нет, даже 3. Потому что запуск в эксклюзивном потоке и на тред пуле — две большие разницы.
TargetSan
11.05.2017 11:29+1Хотя нет, если http://en.cppreference.com/w/cpp/thread/async ничего не упускает — всегда или новый поток, или ленивое значение. Однако это всё равно крайне плохое решение. Во-первых, это таки смешивание двух совершенно разных вещей в одну кучу. Во-вторых, что гораздо хуже, выбор производится флагами (!), да к тому же если указаны оба флага, выбор implementation-defined (!!!). В общем грусть-печаль от такой стандартной библиотеки.
Revertis
Команда разработчиков Раста просто молодцы. Всегда с удовольствием читаю их посты о новых версиях.
В начале года они пообещали, что этот год пройдёт под эгидой упрощения разработки и снижения порога входа, и они держат свои обещания.
Halt
Могу посоветовать поглядывать в регулярно обновляющийся milestone predictions, дабы быть в курсе относительно планируемого времени интеграции фич.
Очень жаль, что impl Trait находится в неопределенном состоянии (на то имеются веские причины). А остальное вполне движется. Я уже несколько месяцев пользуюсь VSCode + RLS и оно «просто работает».
Не уверен что я прав, но похоже RLS используюет инкрементальную компиляцию, что в последнее время здорово ускорило анализ изменений. Это помимо того, что они запилили специальный режим работы компилятора, который выполняет только проходы, необходимые для сбора информации о коде (без лишней кодогенерации).
А с учетом того что все это теперь распространяется через rustup, то начать пользоваться можно в пару команд.