LINUX.ORG.RU

Rust 1.12

 


1

6

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

Новое в 1.12

По словам разработчиков, релиз 1.12 является, возможно, самым значительным с момента выпуска релиза 1.0. Самое заметное для пользователей изменение в версии 1.12 — это новый формат ошибок, выдаваемых rustc. Сообществом была проделана многочасовая работа по переводу вывода ошибок на новый формат. Кроме того, для лучшей интеграции и взаимодействия со средой разработки и другим инструментарием ошибки теперь можно выводить в формате JSON при помощи специального флага --error-format=json.

Самое большое внутреннее изменение — это переход на новый формат внутреннего представления программы MIR. Незаметное сегодня, это изменение открывает путь к череде будущих оптимизаций компилятора, и для некоторых кодовых баз оно уже показывает улучшения времени компиляции и уменьшение размера кода. Переход на MIR открывает ранее сложнодоступные возможности анализа и оптимизации. Первое из многочисленных грядущих изменений — переписывание прохода, генерирующего промежуточное представление LLVM, того, что rustc называет «трансляцией». После многомесячных усилий новый бэкенд, основанный на MIR, доказал, что готов к реальной работе. MIR содержит точную информацию о потоке управления программы, поэтому компилятор точно знает, перемещены типы или нет. Это значит, что он статически получает информацию о том, нужно ли выполнять деструктор значения. В случаях, когда значение может быть перемещено или не перемещено в конце области действия, компилятор просто использует флаг из одного бита на стеке, что, в свою очередь, проще для оптимизации проходов в LLVM. Конечный результат — уменьшенный объем работы компилятора и менее раздутый код во время исполнения.

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

  • Множество мелких улучшений документации.
  • rustc теперь поддерживает три новые цели MUSL на платформе ARM: arm-unknown-linux-musleabi, arm-unknown-linux-musleabihf и armv7-unknown-linux-musleabihf. Эти цели поддерживают статически скомпонованные бинарные файлы. Однако, в собранном виде они пока не распространяются.
  • Повышена читабельность описаний ошибок в ссылках и неизвестных числовых типах.
  • Компилятор теперь может быть собран с LLVM 3.9.
  • Тестовые бинарные файлы теперь поддерживают аргумент --test-threads для указания количества потоков для запуска тестов, который действует точно так же, как переменная окружения RUST_TEST_THREADS.
  • В случае продолжительности выполнения тестов больше минуты показывается предупреждение.
  • Вместе с выпусками Rust теперь доступны пакеты с исходными кодами, которые можно установить при помощи rustup через команду % rustup component add rust-src. Исходные коды могут быть использованы для интеграции и взаимодействия со средой разработки и другим инструментарием.
  • Ускорено обновление индекса реестра.
  • cargo new получил флаг --lib.
  • Добавлен вывод профиля сборки (release/debug) после компиляции.
  • cargo publish получил флаг --dry-run.
  • Сокеты на Linux в подпроцессах теперь закрываются правильно через вызов SOCK_CLOEXEC.
  • Определения Unicode обновлены до 9.0.

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

  • Cell::as_ptr и RefCell::as_ptr.
  • IpAddr, Ivp4Addr и Ipv6Addr получили несколько новых методов.
  • LinkedList и VecDeque теперь имеют новый метод contains.
  • iter::Product и iter::Sum.
  • Option реализует From для содержащегося в нём типа.
  • Cell, RefCell и UnsafeCell реализует From для содержащихся в них типах.
  • Cow<str> реализует FromIterator для char, &str и String.
  • String реализует AddAssign.

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

Самая большая возможность, добавленная в Cargo в этом цикле — «рабочие области». Описанные в RFC 1525, рабочие области позволяют группе пакетов разделять один общий файл Cargo.lock. Это позволяет намного легче придерживаться единственной версии общих зависимостей при наличии у вас проекта, который делится на несколько пакетов. Для включения этой возможности в большинстве мультипакетных проектов достаточно добавить одну единственную строчку [workspace] в Cargo.toml верхнего уровня, более сложным установкам может потребоваться дополнительная настройка.

Другая существенная возможность — переопределение источника пакета. При помощи инструментов cargo-vendor и cargo-local-registry можно переопределять зависимости локально (vendoring). Со временем это станет фундаментом для построения инфраструктуры зеркал crates.io.

>>> Подробный список изменений

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

★★★★★

Проверено: Falcon-peregrinus ()
Последнее исправление: Falcon-peregrinus (всего исправлений: 10)

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

В наследовании интерфейсов. В динамически-типизрованных языках этих заморочек нет. Ваш К.О.

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

Как, например, наличие лямбд не делает C++, Java и C# функциональными языками.

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

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

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

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

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

Ты тут на каждый мой комментарий будешь высказывать своё неповторимое особое мнение?

Почему бы и нет? Тебе же никто не мешает бредить про инкапсуляцию.

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

Ну то есть, возражений нет? И в С++ точно так же можно размазать реализацию, только оно ещё и может внезапно выстрелить благодаря ADL.

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

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

Хорошо, тогда разве этого в расте нет?

Если что, мне совершенно не интересно доказывать «полноценность ООП» в расте. А вот с отсутствием инкапсуляции категорически не согласен.

Кстати, не отрицаю, что в С++ всяких «связанных с ООП штук» больше - это очевидно. Другое дело, что отношение к вещам типа protected и friend неоднозначное. Да, оно бывает весьма удобно, но не факт, что в языке с наличием других механизмом оно необходимо. Тут я пока не определился.

В общем-то, с наследованием данных примерно так же. Большинство ООП-приёмов к языку и так применимы, разве что выглядеть могут несколько иначе. Проблемой оно становится только если для достижения целей приходится писать «мусорный» код. Такие места в языке, к сожалению, есть. Но есть и надежда на исправление таких вещей.

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

в языке с нормальным множественным наследованием отдельное понятие интерфейса является лишней (т.е. не нужной) сущностью.

Тем не менее, логическое понятие осталось. Просто потому что выделять «интерфейс объекта» - это удобно. И не суть важно как он представлен: в виде «честного интерфейса», в виде абстрактного (или не очень) базового класса, в виде документации (для динамически типизированных языков) или даже в виде концептов (тоже ведь «интерфейс», пусть и для шаблонов). Главное, что оперировать таким понятием удобно.

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

Хорошо, тогда разве этого в расте нет?

Об этом уже говорилось. Интересная фишка Rust-а в том, что у нас может быть некая структура S и некий трейт T, которые появились независимо друг от друга. И если какому-нибудь Васе Пупкину потребуется использовать экземпляры S там, где ожидается T, то Вася Пупкин может реализовать T для S. Не спрашивая разрешения у авторов S и T.

Это интересная фича.

Но, имхо, пользу она приносит тогда, когда содержимое S открыто. Тогда Вася Пупкин не имеет препятствий для реализации T.

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

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

eao197 ★★★★★
()

DarkEld3r, eao197 Да это же адекваты в треде. Слава ктулху, наконец-то.

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

И если какому-нибудь Васе Пупкину потребуется использовать экземпляры S там, где ожидается T, то Вася Пупкин может реализовать T для S. Не спрашивая разрешения у авторов S и T.

Не получится. Раст позволяет имплементить любой интерфейс для типа из текущего модуля, либо интерфейс из текущего модуля для любого типа.

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

Не получится. Раст позволяет имплементить любой интерфейс для типа из текущего модуля, либо интерфейс из текущего модуля для любого типа.

Хм... похоже, прежде чем на раст можно будет посмотреть я на пенсию уйду.

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

Ну то есть, возражений нет? И в С++ точно так же можно размазать реализацию, только оно ещё и может внезапно выстрелить благодаря ADL.

В C++ точно так же «размазать» ничего нельзя, потому что поведение определяется в интерфейсе, который ты наследованием не поменяешь. Вы, растаманы, просто органически не отличаете интерфейс от реализации. Кроме того, наследованием ты создаёшь новый тип, что тоже легко отслеживается при желании.

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

Какие обширные обоснованные выкладки касательно психологии незнакомых людей. Гаданием по картам занимаешься в перерывах между go и ocaml?

Мальчик, я жизнь прожил, видел таких.

Или работать на крупные компании за деньги достаточные, чтобы не клянчить подачек на зимнюю резину за баги — не достаточно по-хипстерски?

За 200 баксов? Месяц работать? Да ты ебанцтый.

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

Что «no comment»?
Ты пальцем показать можешь в каком там месте protected-член и доступ к нему?

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

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

В С#, Vala, Java есть. В С++ вроде нету, там абстрактными классами выкручиваются.

Хочется что-то типа:

interface B {void f();}
class A1: B {}
class A2: B {}

B ar=new Array<B>();
A1 a11=new A1();
A2 a22=new A2();
ar.insert(a11 as B);
ar.insert(a22 as B);

foreach(a in ar){a.f();}

void_ptr ★★★★
()
Последнее исправление: void_ptr (всего исправлений: 1)
Ответ на: комментарий от void_ptr
pub trait B {fn f(&self) {} }

pub struct A1 {}
pub struct A2 {}

impl B for A1 {}
impl B for A2 {}

fn main() {
    let vs = vec![Box::new(A1{}) as Box<B>, Box::new(A2{})];
    for v in vs {
        v.f();
    }
}
red75prim ★★★
()
Ответ на: комментарий от tailgunner

приведенный выше трюк с перегрузкой Deref вполне жизнеспособен.

Ну это всё-таки уродство и, как по мне, справедливо считается антипаттерном.

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

Прошу немного, долларов 200, резину надо менять, винтер из каминг)

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

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

Это уже совсем другой вопрос.

Зато более важный на практике.

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

Хочется что-то типа

Руст - системный язык, там неявной ссылочной семантики нет и не будет.

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

А у тебя есть full-time вакансии под rust? Город какой?

С полгода назад видел вакансию: full-time с возможностью удалённой работы (вроде). Украина/Киев. Искать лень, но могу попробовать, если на слово не поверишь.

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

так может, контролировать надо не в предке (поставщике интерфейса), а в потомке (потребителе) ?

Дык, я отвечал на претензию в духе «кто-то может реализовать неправильное поведение».

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

Исключения можно найти из любого правила.

Вот только, вопреки популярному заблуждению, это не подтверждает правило.

Особенно если речь заходит про Lisp-ы, в которых каждый может создать себе какого угодно уродца.

Это всё-таки функциональность из коробки, а не сторонняя либа. Ну и возможность «создать какого угодно уродца», как по мне, является плюсом.

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

Вот только, вопреки популярному заблуждению, это не подтверждает правило.

SmallTalk, Ruby, Python, Self, JavaScript — нет такой языковой сущности, как интерфейс. Это не правило, это случайность. Я понял.

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

Вася Пупкин может реализовать T для S. Не спрашивая разрешения у авторов S и T.

Напрямую это сделать нельзя, но да, ограничение можно обойти.

Вот только разве в С++ не точно так же? Можно наследоваться от чужого интерфейса (а трейт - это, в принципе, интерфейс) и одновременно от чужого типа (ну или заменить агрегацией) и подсунуть эту обёртку. Тоже не спрашивая авторов.

Но, имхо, пользу она приносит тогда, когда содержимое S открыто. Тогда Вася Пупкин не имеет препятствий для реализации T.

Не обязательно. Васе может хватить публичного интерфейса S.

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

Вот мне и интересно услышать в чём именно оно проявляется. Отсутствие frient, protected - понятно. «Необходимость» использовать модули, а не классы для сокрытия, как по мне, принципиально ничего не меняет. Что-нибудь ещё?

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

Хм... похоже, прежде чем на раст можно будет посмотреть я на пенсию уйду.

Почему? Тебе кажется, что это слишком сильное ограничение?

Вот только если обращаться к аналогиям, то всё нормально. Возьмём плюсы: в либе A есть интерфейс I, в либе B тип T. Нельзя взять и реализовать интерфейс именно для этого типа (не трогая исходники). Зато можно сделать обёртку:

class W : public A::I, public B::T {
    ...
}
И в расте можно сделать похожим образом.

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

В C++ точно так же «размазать» ничего нельзя, потому что поведение определяется в интерфейсе

Ну давай в терминах плюсов. Есть интерфейс Crawler и класс Snail, который от него наследуется. Дальше я делаю FlyingSnail и в реализации метода crawl лечу. Ну прямо как ты показываешь в соседнем примере кода.

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

Вы, растаманы, просто органически не отличаете интерфейс от реализации.

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

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

Хочется что-то типа:

Дык, в массиве будут лежать не сами объекты, а указатели - так и в расте сделать можно.

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

Вот только разве в С++ не точно так же?

Если S — это struct, а T — это абстрактный класс, то можно. Только вот в общем случае в C++ S не будет структурой. И наружу не будут торчать детали, необходимые для реализации T.

«Необходимость» использовать модули, а не классы для сокрытия, как по мне, принципиально ничего не меняет.

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

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

но могу попробовать, если на слово не поверишь

Не трать время. Тем более, что на фоне всей этой нацпольной истерии мне украина никаким боком не актуальна. За инфу спасибо

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

SmallTalk, Ruby, Python, Self, JavaScript — нет такой языковой сущности, как интерфейс. Это не правило, это случайность. Я понял.

Изначально утверждалось, что «в динамические типизированных языках не бывает интерфейсов». Я рад, что ты согласен, что это не так. Но можем пойти и дальше.

В Pharo (реализация Smalltalk) есть трейты, которые представляют собой как раз интерфейсы.

В Ruby, вроде, совсем ничего такого нет, да. Хотя есть статьи и рукопашные реализации. Даже интересно зачем на это идут программисты на вполне приличном языке, таким же только извращенцы-лисперы должны заниматься?..

В Python есть абстрактные базовые классы и, опять же, наколеночные реализации. Если что, про их популярность ничего говорить не собираюсь.

В JavaScript interface, вроде, является зарезервированным ключевым словом? Может когда-нибудь что-то и добавят на эту тему. (:

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

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

И наружу не будут торчать детали, необходимые для реализации T.

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

Ну не меняет, ну что тут поделать.

Просто из любопытства: а если взять привычный С++ и заменить public/private на какие-нибудь другие ключевые слова инкапсуляция станет «своеобразной»? А если запретить группировать данные/методы и требовать указания перед каждым? Или пусть доступность зависит от кейса первой буквы поля/функции. Или же сделать так, чтобы это перед классом перечислялось, как-то так:

class C [public: a, b, c, private: d, e] { ... }
В общем, где грань проходит? (:

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

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

Очевидно, что некий API, за который можно дергать объекты, является интерфейсом. И интерфейс, как логическое понятие, архиважен, т.к. без интерфейса не понятно, как выражать этот самый API.

Однако, речь идет не о понятии, а об отдельной языковой сущности. Надобность в которой есть в статически-типизированных языках (ибо в компайл-тайме нужно проверять допустимость вызова). А вот для динамических, как показывает обширный опыт, — нет. По большому счету duck typing как раз и базируется на том, что нет этих самых интерфейсов как языковых сущностей.

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

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

Видимо, ваше знание Rust-а намного лучше моего. Я, например, полагал, что если в модуле m1 есть структура S, а в модуле m2 — трейт T, то Вася Пупкин в модуле m3 может сделать свою имплементацию T для S.

Мне казалось, что это очень интересная фича. Возможно, одна из killer features языка.

Но, как мне тут указали, я не прав. Вася Пупкин может сделать имплементацию T только в модуле m2. Что, имхо, превращает эту воображаемую фичу в пшик. Но Rust-оманам нравится, так что пусть балуются.

В общем, где грань проходит? (:

У устоявшихся привычках. Как-то так повелось, что в ООЯ единицей инкапсуляции является класс (или объект, если уж речь про прототипные ООЯ). Исключения, конечно же, можно найти. В частности в Java есть package visibitility. Но, в тех ООЯ, с которыми доводилось работать, все-таки инкапсуляция замыкалась на класс/объект. И к этому привыкаешь.

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

Но Rust-оманам нравится, так что пусть балуются.

Позволь спросить, а если это будет не Rust, то Вася реализует T для S, Петя T для S, Ваня T для S, и т.д.?

Нет уж, пусть лучше владельцы T или S реализуют T для S.

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

Позволь спросить, а если это будет не Rust, то Вася реализует T для S, Петя T для S, Ваня T для S, и т.д.?

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

Нет уж, пусть лучше владельцы T или S реализуют T для S.

Аминь.

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

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

Ладно, ты не понял, объясню ещё раз.

Вася реализовал T для S в пакете A.
Петя реализовал T для S в пакете B.
Ваня реализовал T для S в пакете С.

Ты используешь пакеты A, B и C.

Какую из реализаций ты будешь использовать?

Как указать компилятору, что именно эту реализацию использовать? Может что-то типо?

// crate X
trait T {}

// crate A
impl T(impl_identifier) for S {}

// your crate
use A::impl_identifier;

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

А разве это не решается введением в область видимости только одной реализации из нужного мне пакета?

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

Так здесь проблемы нет до тех пор, пока я не создам объект B::S и не попытаюсь привести его к A::T. Вот в этом случае компилятор может сказать, что приведение неоднозначно.

Собственно, в C++ вы можете определить int f(int) в пространствах имен A и B. Если вы сделаете using namespace A и using namespace B одновременно, то не сможете просто вызвать f(0). Вам придется уточнить имя f.

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

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

«Набор функций» в интерфейсе - это и есть поведение, а их реализация - это уже другой шаг. Ты можешь сколько угодно стрелять себе в ногу реализуя полеты в методе crawl. Это не одно и тоже, что прилепить новый интерфейс к тому же самому объекту. Вот я поэтому и пишу, что вы просто органически не отличаете интерфейс от реализации.

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

...и верно это для всех языков, кроме C...

не, серьёзно. до сих пор что-то никто не понимает, что крутизна C-либ не только в том, что быстрое, а ещё в том, что напишут к ним 20 биндингов и всё, оно везде, на всех языках. ради чего и небезопасность терпят...

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

до сих пор что-то никто не понимает, что крутизна C-либ

В самом Си нет крутизны - устаревший убогий язычок.

напишут к ним 20 биндингов и всё, оно везде, на всех языках. ради чего и небезопасность терпят...

А говорить, что либы на Си круты потому, что у них относительно простой ABI - это оскорбление авторам либ.

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

В туевой хуче компилируемых языков можно экспортировать си-совместимый API. Даже в Go.
И хоть обмажься биндингами.

P.S. А если писать на Vala, они еще и сами сгенерятся

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

я к тому, что на какой-нить яве это хрен сделаешь...

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