LINUX.ORG.RU

Rust 1.18

 


1

10

Команда Rust анонсирует релиз 1.18.

Обновление предыдущей версии легко:

$ rustup update stable

Сам rustup можно установить здесь.

Основные изменения

Одно из главных изменений - новая версия «The Rust Programming Language», официального учебника по Rust. Он пишется открыто на Github, и имеет более ста авторов. В этом релизе включен черновик второй версии книги, имеющий 19 из 20 глав; двадцатая глава будет готова к релизу 1.19. Купить бумажную версию можно через No Starch Press. Новая версия книги полностью переписана и учитывает последние два года нашего опыта обучения Rust. Вы найдете новые объяснения основных принципов Rust, новые проекты и прочее.

В самом языке улучшено ключевое слово pub. По умолчанию, в Rust объекты приватны; можно использовать pub чтобы сделать их публичными. В Rust 1.18, pub имеет новый вариант:

pub(crate) bar;

Слово в скобках - ограничение, контролирующее степень публичности объекта. Если указанно pub(crate), то bar будет публичным для всего крейта (пакета), но не вне него. Это позволяет декларировать интерфейсы, «внутренне публичные» для пакета, но не доступные для внешних пользователей.

Также можно указать путь, например:

pub(in a::b::c) foo;

Это значит «доступно в иерархии a::b::c, но не в прочих местах».

Для пользователей Windows Rust 1.18 имеет новый атрибут, #![windows_subsystem]. Он работает так:

#![windows_subsystem(console)]
#![windows_subsystem(windows)]

Он контролирует флаг /SUBSYSTEM в компоновщике. На текущий момент доступны только console и windows. Если вы разрабатываете графическое приложение, и не указываете windows, в момент пуска программы всплывет окно консоли. С атрибутом windows этого не произойдет.

Далее, в Rust кортежи, варианты перечисляемых типов и структуры (без атрибута #[repr]) всегда имели неопределенное расположение в памяти. Мы включили автоматическое упорядочивание, которое может привести к уменьшению потребления памяти путем уменьшения необходимого выравнивания. Например:

struct Suboptimal(u8, u16, u8);

В прежних версиях Rust на платформе x86_64 эта структура имела бы размер в шесть байтов. Но согласно исходному коду, ей достаточно должно быть четырех. Остальные два байта - результат выравнивания. Поскольку мы имеем u16, он требует двух байтов. Но в данном случае, он был смещен на один байт из-за предыдущего u8. Для последнего же u8 требуется еще один байт выравнивая. В итоге, мы имеем 1 + 1 (пусто) + 2 + 1 + 1 (пусто) = 6 байтов.

Но что если структура выглядит так?

struct Optimal(u8, u8, u16);

Эта структура оптимально выравнена; u16 находится на рубеже двух байтов, как и остальная структура. Выравнивание не требуется. Это дает нам 1 + 1 + 2 = 4 байта.

При дизайне Rust мы оставили физическое расположение данных в памяти неопределенным как-раз по этой причине; любой safe-код (не следующий по «сырым» указателям) не будет затронут подобной оптимизацией. Благодаря этому, мы можем научить компилятор оптимизировать Suboptimal в Optimal автоматически. В Rust 1.18 обе структуры занимают в памяти размер в четыре байта.

Мы долго планировали это изменение; оно было и ранее в нестабильной версии Rust, но некоторые программисты писали unsafe-код, который предполагал определенное расположение данных в памяти. Если вам необходима гарантия, что физическое расположение в памяти в точности совпадает с расположением вариантов в исходном коде (например, при обращению к оболочкам Cи-кода), пометьте вашу структуру с атрибутом #[repr(C)].

Напоследок, улучшено время компиляции; например, компиляция самого rustc теперь на 15%-20% быстрее.

Стабилизированы следующие библиотеки:

  • Child::try_wait, неблокирующая форма Child::wait.
  • HashMap::retain и HashSet::retain - версия существующего retain от Vec<T> теперь и у этих двух структур.
  • PeekMut::pop позволяет взять ранее прочитанный верхний элемент от BinaryHeap<T> без необходимости повторно упорядочивать кучу.
  • TcpStream::peek, UdpSocket::peek, UdpSocket::peek_from позволяют прочесть крайний элемент у потока или сокета.

Новый функционал Cargo

Cargo добавил поддержку системы управления версиями Pijul, который написан на Rust:

cargo new my-awesome-project --vcs=pijul

У Cargo несколько новых флагов, дополняющих --all: --bins, --examples, --tests и --benches позволяют собрать все программы указанных типов.

И наконец, Cargo теперь поддерживает Haiku и Android.

Подробнее об изменениях написано здесь.

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



Проверено: Shaman007 ()
Последнее исправление: cetjs2 (всего исправлений: 7)
Ответ на: комментарий от gene1

Ну как бы до 1.0 Box был через @ или ~, уже не помню. Выкинули, ибо и так много спец. символов.

Ну и не будем забывать, что кроме Box есть ещё Rc, Arc и любой другой контейнер, какой тебе захочется. Делать Box частью языка - не очень (хотя он является частью компилятора, а не только std, на самом деле).

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

Даю честное благородное слово прочитать пару глав перед тем, как продолжить обсуждать читабельность растокода.

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

Box не так уж часто используется. Кроме него есть Rc - однопоточный shared_ptr, Arc - многопоточный shared_ptr, & - константный заимствующий ненулевой указатель, &mut - неконстантный заимствующий ненулевой указатель, * - константный просто указатель, *mut - неконстантный просто указатель.

И - да, они все нужны, семантика разная.

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

Дык, в самых первых настах это так и было (там были указатели с @ и ~). Его так поливали говном ещё со времен Циклона, что в конце концов выпилили.

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

Если он хоть как-то влияет на результат компиляции, то это часть языка. Пусть может и не ключевое слово (что странно).

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

Есть экспериментальная фича чтобы вместо `Box::new(x)` писать `box x`. но ее еще не стабилизировали

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

Rc и Arc значительно меняют семантику кода, и используются сравнительно нечасто. Тот случай как раз, когда явность лучше скрытности.

А Box используется чуть менее, чем везде, и при этом работает (с точки зрения результата, а не системы лайфтаймов) практически так же, как &foo.

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

Аналитика с потолка? У меня вот полно Rc и ни одного Box.

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

Если он хоть как-то влияет на результат компиляции, то это часть языка

Всё влияет на результат компиляции.

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

В любом случае нужно будет вводить новые символы — это заканчивается Циклоном и Перлом.

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

Другое дело, что Box используется так часто (и намного чаще, чем сырой указатель, доступный лишь в unsafe-коде), что следовало бы сделать символ *foo эквивалентом Box<foo>

Не пойму, ты хочешь, чтобы создание Box'а выглядело, как let obj = *Obj? Это же наркомания.

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

unwrap() - это для всяких там поделок, а в проде, мол, нужно ошибки обрабатывать честно. Нет, оказывается. Или установки поменялись?

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

Асинхронный резолвер... на куче потоков!

Вы хоть код почитайте сначала, запустите там например.
Асинхронных резолвер не на куче потоков. А на NCPU потоков планируется M/NCPU асинхронных задач.

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

Это же наркомания.

В чем? Хотели форсировать указатель, получили то что просили. А что он не сырой, как в Сях, ну так в Расте вся семантика и так другая, нет смысла в слепую копировать символы.

Спецсимволы в синтаксе языка - на вес золота. Они должны отображать самый частый и семантичный код. Box - стандартный, семантичный Раст; сырой указатель - нет.

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

Нормальное объявление подобной функции в любом другом языке можете увидеть.

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

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

В чем?

В первую очередь в том, что это синтаксис разыменования.

Спецсимволы в синтаксе языка - на вес золота. Они должны отображать самый частый и семантичный код.

Всё, что можно реализовать библиотекой, надо реализовать библиотекой.

И вообще, уже приняли rfc, согласно которому создание Box'a выглядит так:

let obj = box Obj::new();
Esper
()
Ответ на: комментарий от gene1

А Box используется чуть менее, чем везде,

Совсем в этом не уверен. Хотя в исходниках Rust Box, кажется, встречается чаще.

Использовать Box внутри структуры имеет смысл только для хранения трейт-объекта, рекурсивных типов, типа, который не поместится на стеке, или unsized типа, но для последних двух вариантов обычно больше подходит Vec или специальный тип вроде String. Для хранения на стеке - всё то же самое.

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

Вроде, от укороченного Box отказались ещё на этапе становления 1.0.

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

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

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

Вы хоть код почитайте сначала, запустите там например.
Асинхронных резолвер не на куче потоков. А на NCPU потоков планируется M/NCPU асинхронных задач.

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

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

Смысл в том, что такие вещи правильно делать на сопрограммах

По вашему futures и tokio не достаточно асинхронны? А то что у них epoll(kqueue) под капотом тоже не считается?

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

По вашему futures и tokio не достаточно асинхронны? А то что у них epoll(kqueue) под капотом тоже не считается?

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

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

В языках с исключениями можно не ронять всю библиотеку (и использующую её программу) даже если тебе лень возиться с обработкой — просто отлавливаешь всё в самом верху, минимально обрабатываешь и возвращаешь тому, кто тебя вызывал.

В Rust так и есть. Паника это те же исключения, как бы они от них не отнекивались.

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

Ну как бы до 1.0 Box был через @ или ~, уже не помню.

Да, использовалась для обозначения тильда «~».

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

отсутствия обобщенного механизма для этих вещей на уровне библиотеки/языка.

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

код просто переусложнен

Ну и что тут переусложненого в этом асинхронном коде:

let future = future.map(move |msg| msg.extract_answer(query_type))
            .then(move |rv| rv.report_status(&name, status_tx))
            .then(move |rv| rv.partial_ok());

Box::new(future)
Тебе надо слово «async» написать чтобы понятно стало?

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

https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

«It is not recommended to use this function for a general try/catch mechanism. The Result type is more appropriate to use for functions that can fail on a regular basis. Additionally, this function is not guaranteed to catch all panics, see the „Notes“ section below.»

То есть да, сэр, извольте вручную перетаскивать результат из фрейма в фрейм, а не ловить покемонов исключения на верхнем уровне. С другой стороны, Си и Плюсы работают на таком же принципе - разве что там статус код вместо структурного результата.

Для относительной эргономичности есть волшебный костыль: ?.

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

Ну и что тут переусложненого в этом асинхронном коде:

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

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)

Тред о Расте и не единой реплики tailgunner'а, отпал от секты?

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

Я по наивности думал, что вам хочется чего-то выяснить, а вам лишь бы хоть что-то возразить, после того, как не смогли внятно объяснить, зачем расту синтаксис лямбд как у шарпа/скалы (вы пытались немного приврать, назвав это «как у всех»), если весь остальной синтаксис у него «не как у всех».

Что до вашей последней соломинки, ок, я погуглил. Нашёл 2 разных пропозала про лямбды, поданных почти одновременно и за полтора года до выхода 3го шарпа. Доказать, что читал статью с фантазиями «что ждать от следующих плюсов» до 2005го я не могу, но для того, чтоб подтвердить, что до начала обсуждения лямбд в плюсах никакого общепринятого синтаксиса лямбд в си подобных языках не было этого достаточно.

Ну и ругать от Раст за отказ следовать синтаксису даже не самых популярных среди C-подобных - это просто свинство.

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

В языках с исключениями можно не ронять всю библиотеку

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

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

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

Это не библиотека, это утилита. Если бы я все задачи выполнял асинхронно в одном потоке, вас бы это успокоило?
Успокоились? А теперь подумайте в чем разница между запуском асинхронных задач на одном планировщике и на NCPU планировщиков? (подскажу, скорость ~ в NCPU раз выше)

А так же чтобы не несли подобный бред про сопрограммы, почитайте что такое futures-rs и какую задачу эта библиотека выполняет.

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

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

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

Я по наивности думал, что вам хочется чего-то выяснить

Вы что-то себе выдумали. Я сказал, что синтаксис Rust-а мне не нравится, что читать из-за этого синтаксиса чужой код сложнее, чем на других языках и попытался, отвечая на вопросы Rust-оманов, объяснить почему. Не более того.

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

У меня не было цели объяснять зачем Rust-у синтаксис лямб из Scala/C#. Речь о том, что синтаксис лямбд Rust-а не похож на синтаксис лямбд из других языков.

Это вы, кстати, зачем-то уменьшили множество до C++/Rust/Java/C#. Добавьте к этому списку Scala, Python, Ruby, Haskell, OCaml, Erlang и пр. Для меня вовсе не принципиально, чтобы лямбды Rust-а были похожи на лямбды из Scala/C#. Хоть бы они вообще на что-то знакомое были похожи (таки да, least surprise principle).

Нашёл 2 разных пропозала про лямбды, поданных почти одновременно и за полтора года до выхода 3го шарпа. Доказать, что читал статью с фантазиями «что ждать от следующих плюсов» до 2005го я не могу

Важно, что вы не можете доказать вот это:

В плюсах о планах на лямбды я где-то в начале 2000х читал, так что, скорее всего, текущий синтаксис году к 2005му более-менее устаканился.

Если в 2005-2006 было два разных пропозала, значит тезис об «более-менее устаканился» не подтвердился. В чем я и не сомневался.

Ну и ругать от Раст за отказ следовать синтаксису даже не самых популярных среди C-подобных - это просто свинство.

Какие здесь растоманы нежные. Кому-то не нравится синтаксис Python-а, кому-то не нравится синтаксис Ruby, кому-то не нравится синтаксис C++, кому-то не нравится синтаксис Eiffel-я. Вообще-то это нормально. Мне вот не нравится синтаксис Rust-а. Только это, внезапно, «просто свинство».

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

почему нет неявного ап-каста u32 туда, где нужен u64

чтобы type inference был однозначный; и так Deref по три раза в каждой строчке, если добавить еще неявных кастов, будет путаница

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

Это объявление действительно кому-то нравится?

ты еще в std не заглядывал. после того, что там, это определение воспринимается сходу

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

Но то, что имя типа может быть как перед ":", так и после, внушаить

class Oh : public Really {

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

Если серьезно спрашиваешь, то мне нравится. Потому что просто и понятно. «S - любой класс из которого можно получить &str»

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

Хорошее замечание. Но делать @foo явно плохая идея. Я еще немного пригораю из-за того что синтаксис вида

let a = box foo()
сделали unstable и вместо него заставляют использовать
let a = Box::new(foo())
Ну реально же box нужен часто да и вообще это примитив в отличии от того же Rc.

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

Хм. Забавно. Но я так понял это нужно для placement new, которого сейчас нету. В общем посмотрим.

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

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

Потому прагматичный взгляд на раст не прокатывает.

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

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

Наверное, рекомендую начать отсюда https://doc.rust-lang.org/stable/std/rc/ (кстати, не понимаю почему это сразу не добавили в растовую доку, ведь после этого все более-менее проясняется как программить на расте) после того как почитаешь вот это https://doc.rust-lang.org/book/second-edition/ch04-00-understanding-ownership...

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

В каждой строчке провокация... Да Вам Батенька в политику надо, а не к раст-оманам =)

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

Ну а ты как человек с гигантским кругозором, наверное можешь указать нам с высоты на лучшую альтернативу?

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

Подожди, где здесь библиотека?

Здесь https://github.com/mersinvald/batch_resolve/tree/master/src/resolve ?

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

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

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

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

pub fn thread_main(mut self, dns_list: Vec<SocketAddr>) {
        let duration_second = Duration::from_secs(1);

        while self.triggered.get() < self.tasks_cnt {
            let start = Instant::now();
            self.trigger_qps(&dns_list);
            let end = Instant::now();

            let diff = end - start;
            if diff < duration_second {
                thread::sleep(duration_second - diff);
            }
        }
    }
asaw ★★★★★
()
Ответ на: комментарий от mersinvald

А теперь подумайте в чем разница между запуском асинхронных задач на одном планировщике и на NCPU планировщиков? (подскажу, скорость ~ в NCPU раз выше)

Вообще-то она может легко быть в ~NCPU раз ниже только из-за накладных расходов. При условии, что асинхронный код написан правильно, конечно.

asaw ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.