LINUX.ORG.RU

Rust 1.15

 


2

10

Представлен релиз Rust 1.15 — системного языка программирования, нацеленного на безопасную работу с памятью, скорость и параллельное выполнение кода. В этот релиз вошли 1443 патча.

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

$ rustup update stable
или же следуя инструкции на соответствующей странице.

Стабильная версия, наконец-то, увидела долгожданную возможность: пользовательские расширения (custom derive)! К примеру, в Rust вы всегда могли автоматически реализовать некоторые типажи через атрибут derive:

#[derive(Debug)]
struct Pet {
    name: String,
}
В примере выше была определена реализация типажа Debug для структуры Pet с использованием минимального кода. Однако, это работало только для тех типажей, которые являлись частью стандартной библиотеки; пользователям это было недоступно. С версии Rust 1.15 это стало доступно. Это значит, что если вы захотите преобразовать структуру Pet в JSON, это так же просто, как добавить Serde в ваш Cargo.toml:
[dependencies]
serde = "0.9"
serde_derive = "0.9"
serde_json = "0.9" 
и добавить новый типаж к Pet:
#[macro_use]
extern crate serde_derive;

extern crate serde_json;

#[derive(Serialize, Deserialize, Debug)]
struct Pet {
    name: String,
}

fn main() {
    let pet = Pet { name: String::from("Ferris") };

    let serialized = serde_json::to_string(&pet).unwrap();
    println!("serialized = {}", serialized);

    let deserialized: Pet = serde_json::from_str(&serialized).unwrap();
    println!("deserialized = {:?}", deserialized);
}
Это выведет:
serialized = {"name":"Ferris"}
deserialized = Pet { name: "Ferris" }
Другой часто используемый вариант — Diesel (новая версия 0.10.0 которого представлена вслед за Rust 1.15). Допустим, у нас есть база данных, состоящая из Pet. Мы можем сделать выборку следующим образом:
// some extern crate and use lines elided here

#[derive(Queryable)]
struct Pet {
    name: String,
}

fn main() {
    use diesel_demo::schema::pets::dsl::*;

    let connection = establish_connection();
    let results = pets
        .limit(5)
        .load::<Pet>(&connection)
        .expect("Error loading pets");

    println!("Displaying {} pets", results.len());
    for pet in results {
        println!("{}", pet.name);
    }
}
Другие примеры с использование Diesel можно посмотреть на сайте.

Такого рода библиотеки являются очень мощными, но полагаются на пользовательские расширения для эргономики. Хотя эти библиотеки и работали прежде на стабильной версии Rust, пользоваться ими было не так удобно, и пользователи предпочитали работать на ночных версиях Rust «из-за Serde и Diesel». Пользовательские расширения являются одними из самых широко-используемых возможностей в ночных версиях Rust. Таким образом, в июле прошлого года была начата работа над RFC 1681 для реализации данной возможности. В августе RFC был принят, претерпел большое количество работы и тестирования и, в итоге, был включен в эту стабильную версию.

Научиться писать свои собственные расширения можно в соответствующей главе книги «The Rust Programming Language».

Хотя больше всего упоминаний в рамках данной возможности пришлось на «Serde и Diesel», есть много других крутых возможностей, которые можно делать при помощи пользовательских расширений: например, derive-new. Ещё больше можно увидеть, посмотрев список обратных зависимостей пакета syn. (syn очень важен для написания пользовательских расширений; для большей информации, смотрите соответствующую главу книги, ссылка на которую приведена выше). Пользовательские расширения были так же известны под названием «макросы 1.1», так как включают в себя основополагающую инфраструктуру для поддержки ещё более мощных возможностей во время компиляции в Rust, под названием «макросы 2.0». Ожидаем услышать больше новостей в этой сфере в будущих релизах.

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

Система сборки Rust была переписана на Rust с использованием Cargo. Теперь это основная система. Процесс был долгим, но наконец-то принес свои плоды. Вся разработка Rust происходит в основной ветке с использованием новой системы сборки, начиная с декабря прошлого года и показывает хорошую работу, ещё один показатель зрелости Cargo. Уже подготовлен PR для полного удаления всех Makefile-ов к версии Rust 1.17. Это позволит rustc напрямую использовать пакеты с crates.io в компиляторе, как это делается в других проектах на Rust.

В Rust появилась поддержка новых платформ 3 уровня: i686-unknown-openbsd, MSP430, и ARMv5TE.

Компилятор получил ряд улучшений производительности. Работы над производительностью компилятора продолжаются от релиза к релизу и в будущем ожидаются ещё больше улучшений.

В качестве незначительного улучшения, ?Sized теперь можно использовать в утверждении where. Другими словами:

struct Foo<T: ?Sized> {
    f: T,
}

struct Foo<T> where T: ?Sized {
    f: T,
}
Вторая форма теперь принимается, и равнозначна первой.

Более подробный список изменений.

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

Алгоритм slice::sort был переписан и теперь гораздо-гораздо быстрее. Применяется гибридная сортировка слиянием, вдохновленная Timsort. Раньше применялась простая сортировка слиянием.

Если у вас имеется Vec<T> где T: Copy с вызовом extend на него, ваш код теперь будет гораздо быстрее.

Говоря о быстродействии, chars().count(), chars().last(), и char_indices().last() теперь тоже быстры!

Китайские символы теперь правильно отображаются в fmt::Debug.

Также были стабилизированы следующие функции:

Более подробный список изменений.

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

Cargo теперь будет выдавать предупреждение, если в верхнем уровне пакета будет файл с названием build.rs, но не будет аннотации build = "build.rs". Это делается из соображения совместимости, так как предполагается использование файла build.rs в верхнем уровне пакета в качестве файла сборки.

В этом релизе, скрипты в Cargo больше не имеют доступа во время сборки к переменной среды окружения OUT_DIR через env!(«OUT_DIR»). Теперь проверку переменной надо осуществлять во время выполнения через std::env. Установка значения переменной во время сборки было ошибкой и некорректной при кросс-компиляции. Проверьте свои пакеты и обновите на использование std::env.

Команда cargo test получила поддержку флага --all, что полезно при работе с рабочими пространствами.

Появилась возможность статической компиляции с использованием MSVC CRT на Windows, и статического связывания OpenSSL на Mac OS X.

Более подробный список изменений.

Страница благодарности

Для выражения благодарности авторам и помощникам, которые делают Rust лучше, запущена новая инициатива «Thanks!» — страница с благодарностью людям, которые внесли вклад в Rust. Страница доступна по адресу https://thanks.rust-lang.org/ (или https://♥.rust-lang.org). Список авторов и помощников за всё время, по количеству коммитов, можно посмотреть здесь: https://thanks.rust-lang.org/rust/all-time. В Rust 1.15 всего был сделан вклад со стороны 137 людей.

>>> Подробности

★★★★★

Проверено: jollheef ()
Последнее исправление: Deleted (всего исправлений: 2)

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

По поводу Rust-а мне сейчас не понятна вот какая штука: насколько низок порог входа в него для не очень опытных разработчиков.

Порог входа довольно высок. В основном из-за непривычности концепций «владения» и «времени жизни». Первое обычно никто не отслеживает, вторым обычно заморачивается либо GC, либо неявно сам программист. А когда за это начинает компилятор бить по рукам, первое время вообще нифига не понятно.

По своему опыту могу сказать, что низкоуровневый(libcore+байто**ство) код писать на расте можно, но там где на си ты за 20 минут сделал и забыл, на расте времени потратить приходится гораздо больше. Если нет навыка.

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

Потому что это не те вещи которым место в stdlib, не говоря уж про синтаксис. Да, это не так удобно когда у тебя всё из коробки, но и не требует реализовывать себя при переносе на другую платформу.

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

но и не требует реализовывать себя при переносе на другую платформу

Как-бы само напрашивается разделение stdlib на tiers )

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

А может это новый тренд.

Это не может. И не новый.

На уровне бизнеса постоянно идет борьба за снижение издержек. Поэтому когда все конкуренты клепают с такой же скоростью софт на Ruby/Python/Erlang, что и ты, то выигрывать нужно за счет удешевления эксплуатации. Нативные языки без жирного рантайма позволяют в разы снижать требования к оборудованию, на котором софт затем крутиться. При этом тот же Go позволяет клепать определенного сорта софт не сильно медленнее Python-а.

По поводу Swift-а история чутка другая, но так же связана с ресурсопотреблением. Apple заинтересована в том, чтобы приложения на iPhone/iPad/iWatch работали шустро, и батарею не сажали за 15 минут. Потому там нативный код и отсутствие GC. Отсюда и вот такой вот Swift на замену древнему Objective-C.

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

В Rust можно сделать let it crash^Wpanic, в Си++ - let it throw.

let it throw в C++ нифига не близок к тому, что дает let it crash в Erlang-е.

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

Тем, что crash — это crash, сбойный процесс просто убивается, все, чем он владел, автоматически освобождается, заинтересованные процессы получают уведомления и т.д.

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

Это если в двух словах.

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

Упавший процесс может быть перезапущен автоматически супервизором. Но это уже от супервизора зависит и от частоты падений процесса.

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

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

Рассуждение доказывало необходимость единой реализации, а не конкретно зеленых нитей под капотом этой реализации. Ну и, ЕМНИП, в Go сначала были родные нити, потом зеленые, так что даже реализация может меняться, но она должна быть общей для всех.

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

Рассуждение доказывало необходимость единой реализации, а не конкретно зеленых нитей под капотом этой реализации

Интересная мысль, кстати. А возможно ли взять текущее Rust API для тредов и вместо pthreads подсунуть ему какую-нибудь реализацию грин тредов. А еще лучше возможность выбирать между pthreads/greenthreads в рантайме

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

Однажды это уже не получилось. Может быть, если сделать второй рантайм и второй бэкенд компилятора, такое и получится, но сейчас это никого не интересует.

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

если сделать второй рантайм и второй бэкенд компилятора

Так сложно? Я думал не сложнее чем написать адаптер к библиотеке

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

Да, так сложно. Внутренности рантайма завязаны на то, какой тип нитей, и в компиляторе тоже есть какие-то завязки.

Ссылки на обсуждение в rust-dev@ сейчас найти не могу, но вот релевантный RFC: https://github.com/rust-lang/rfcs/pull/230

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

Ну так выключай дурочку. Экономь время себе и другим.

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

... On Linux/x86-32, the default stack size for a new thread is 2 megabytes ...

А как это работает? Он сразу реальную память выделяет, или по каким-то 4-КБ страницам? Я предполагаю, что второе. Т.е. хоть он и теоретически выделил 2 мегабайта, но реально от системы память будет требоваться только по факту использования кусками по 4 КБ, т.е. если у тебя стек небольшой, то расход будет 4КБ на тред, а не 2 МБ.

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

Я предполагаю, что второе

Я вообще ничего не предполагаю. Для меня ядерные дела - это черная магия) Но люди же не просто так жалуются, что память жрется

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

Ну кто их знает, чего они жалуются, надо разбираться. Так-то и 2 килобайта немало, плюс, наверняка, ядерные структуры на поток тоже занимают что-нибудь такого же порядка. Плюс переключение процессов сопровождается переключением контекста из пользовательского в ядерный, что почему-то работает медленно (относительно вызова функции планировщика). Т.е. если в ерланге поток требует 100 байтов и переключается быстрее потока ОС, то уже выигрыш на десятичный порядок по памяти и в сколько-то раз по процессору/кешам.

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

Если действительно цифры на стек не такие страшные (килобайты вместо мегабайт), то для большинства задач наверное, проще памяти докинуть, чем с промисами футурами замарачиваться

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

Мне вот не понятно. Допустим, сервер на го держит 10 тыщ спящих коннекшенов, каждый из которых создал по 100 килобайт локальных переменных. При этом нативных тредов, очевидно, создается значительно меньше чем 10 тыщ. Почему не произойдет переполнение стека? Го не использует ОС стэк для локальных переменных?

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

Го не использует ОС стэк для локальных переменных?

У го своя реализация стека.

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

Как устаканиться синтаксис - обязательно попробую использовать в релизных устройствах.

Дык, синтаксис с 1.0 не меняли.

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

Сделать например «строка» с двойными кавычками - сменяемой, а 'строка' с одной - несменяемой, так и не додумались.

Одинарные кавычки - символы. Ну и «весь этот спам» ради явности. Некоторым нравится.

И так во всем.

Например?

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

Разработчик tokio может слиться, либа застагнировать. С Го такого не произойдет, т.к. горутины в самом языке

Это работает и в обратную сторону. Если вдруг придумают что-то новое удобное, то появление его в языке придётся ждать некоторое (иногда долгое) время, а либа появиться может куда быстрее.

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

А если бы еще вариативные аргументы появились, возможно, не нужно было бы использовать маркос чтоб вывести на экран «Hello World» :-)

Макрос проверяет количество и типы аргументов вообще-то.

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

makoven открой курсы программирования на ебланге

заработаешь бабло потом анонимусу лоровскому скажешь спасибо

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

Увы, оно, как другие, работает очень плохо.

Почему? Вроде, более-менее нормально, ну и обновляется регулярно. Разве что дебаг туда не завезли, но автор обещает.

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

Автодополнения фактически нет. Почти все фичи помечены как WIP. Go to definition работает в пределах одного файла/крейта. И тд.

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

Там используется racer, наверное. А он не умеет дополнять макросы(возможно там и другие проблемы есть).

Racer не используется, насколько я знаю. Но макросы дополнять этот плагин и правда не умеет, хотя, как по мне, это меньшая из проблем.

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

Автодополнения фактически нет.

Да, вроде, работает. В «сложных случаях» может и нет, но учитывая, что раньше вообще без дополнения писал, то рад и этому.

Go to definition работает в пределах одного файла/крейта. И тд.

У меня гo to definition сработало для типа из сторонней библиотеки.

В любом случае, видно, что работа идёт. Недавно стала документация для соответствующих extern crate показываться (ну или я недавно на это внимание обратил).

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

Как-то дебажил среднего размера проект на C и там выходило примерно по 20 килобайт стека на поток. Так что да, стек выделяется страницами по немногу а не целым куском в 2 мегабайта. Но суть не в этом. Главное отличие в том что стек go может не только расти но и уменьшаться. На языке без GC такое не сделаешь (сделать то можно, но будет тормозить).

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

RLS подчёркивает ошибки и предупреждения компиляции в коде и показывает тип переменной при наведении на неё. Rusty Code ни того не другого не умеет. но для RLS надо самому собрать исполняемый файл и засунуть в $PATH, а ещё руками поставить экстеншен для vscode из гита

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

Ну автоформатирование кода и переименование переменных могут и съесть что-нибудь, а вот подчёркивание ошибок, всплывающие подсказки и Go To Definition сильно облегчают жизнь, хотя и глючат иногда

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

А еще лучше возможность выбирать между pthreads/greenthreads в рантайме

Что-то отчасти напоминающее это есть в Haskell (forkIO / forkOS). Не совсем точное соответствие, но смысл в том, что мы можем привязать заданный зеленый поток жестко к системному, главным образом, для интеграции с системными либами, которые хотят работать только в одном системном потоке.

Наверное, в go и erlang тоже что-то подобное должно быть?

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

Stackoverflow:

Erlang uses green threads with preemption. This is possible only because Erlang has a VM, which also allows a lot of other things like code hotswap. But languages with VM are unsuitable for systems programming because they always have some constant overhead, both in memory and processing power. Rust is a systems programming language, and so it cannot have a significant runtime system. I'd also add that Erlang is not fast. It is notoriously ineffective in numerical computations, for example - see here. Its concurrency model allows for high throughput for I/O operations, but this is a different thing.

So in order to support green threads in a feasible way a language has to have some kind of runtime. The reasons of runtime removal in Rust are outlined in the corresponding RFC. In short, the runtime model used in Rust at that time was difficult to work with efficiently and hard to improve, while not having sufficient benefits due to implementation problems and general constraints due to the API, so it was scrapped. As far as I know, nothing in principle prevents someone from writing a green thread-based runtime for Rust, just no one did that yet.

Официальное объяснение по Rust: https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1...

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

As far as I know, nothing in principle prevents someone from writing a green thread-based runtime for Rust, just no one did that yet

И, видимо, уже не сделают. В 2017 roadmap упоминают tokio и даже возможность добавить в синтаксис слово yield

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.