LINUX.ORG.RU

Rust 1.49

 


2

6

Опубликован релиз 1.49 языка программирования Rust.

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

Чтобы чётко обозначить, насколько поддерживается каждая система, используется система уровней:

  • Уровень 3. Система поддерживается компилятором, но не предоставляются готовые сборки компилятора и не прогоняются тесты.

  • Уровень 2. Предоставляются готовые сборки компилятора, но не прогоняются тесты

  • Уровень 1. Предоставляются готовые сборки компилятора и проходят все тесты.

Список платформ и уровней поддержки: https://doc.rust-lang.org/stable/rustc/platform-support.html

Новое в релизе 1.49

  • Поддержка 64-bit ARM Linux переведена на уровень 1 (первая система, отличная от систем на x86, получившая поддержку уровня 1)

  • Поддержка 64-bit ARM macOS переведена на уровень 2.

  • Поддержка 64-bit ARM Windows переведена на уровень 2.

  • Добавлена поддержка MIPS32r2 на уровне 3. (используется для микроконтроллеров PIC32)

  • Встроенный тестовый фреймворк теперь выводит консольный вывод, сделанный в другом потоке.

  • Перенесены из Nightly в Stable три функции стандартной библиотеки:

  • Две функции теперь помечены const (доступны на этапе компиляции):

  • Повышены требования к минимальной версии LLVM, теперь это LLVM9 (было LLVM8)

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

★★★★★

Проверено: Shaman007 ()
Последнее исправление: atsym (всего исправлений: 8)
Ответ на: комментарий от Siborgium

Но если у меня нет конструктора, мне нужно знать имя конкретной функции, которой нужно передать аргументы

В подавляющем числе случаев new, иногда билдеры. Да и зачем документация?

Так, эта функция не может быть перегружена

Решается созданием нескольких функций. Необходимость перегрузки - это вкусовщина. Разработчики считают, что не нужно: усложняет вывод типов и чтение кода. Отдельно писать get и get_mut время от времени бесит, но не более того.

Более того, я не могу вызвать функцию для произвольного T – мне придется потребовать для этого T: SomeTrait и реализовывать SomeTrait для моих типов

Можешь, если сам не поставишь констрейнт. Ты не сможешь с ним сделать ничего кроме как переместить, но кроме этого, как правило, в конструкторе ничего и не нужно. А если нужно, то в С++ ты точно также не сможешь сделать с типом того, что для него не реализовано. Так почему бы и не задать необходимые интерфейсы заранее? Опять, иногда это бесит и хочется сказать что-то типа «хрен с тобой, дай мне утиную типизацию», но преимущество в виде человеческих ошибок компиляции тоже есть.

что приводит к невозможности воплощения (обобщенных) conditional move и in-place construction.

Реализуется через замыкания: Foo::with(|| Bar { .. }). На уровне языка, к сожалению, пока еще не гарантируется in-place, но на практике любые копирования выпиливаются в релизе.

С этим нужно что-то делать – и появились статик функции, возвращающие Result<Self, E>.

Снова вкусовщина. Почему это хуже исключений?

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

В подавляющем числе случаев new, иногда билдеры. Да и зачем документация?

Можешь, если сам не поставишь констрейнт.

Нет, не могу.

fn foo<T>() -> T {
    T::new()
}
error[E0599]: no function or associated item named `new` found for type parameter `T` in the current scope
 --> main.rs:4:8
  |
4 |     T::new()
  |        ^^^ function or associated item not found in `T`

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

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

Пусть у меня есть структурка вида

struct S { }

impl S {
    pub fn new() -> Self { S{} }
}

Для нее new реализован. Функция выше все еще не компилируется, даже если я напишу где-нибудь в main

let s: S = foo();

Реализуется через замыкания: Foo::with(|| Bar { .. }).

Не реализуется. Владение безусловно передается в замыкание. Куда оно передастся дальше – неважно, исходный владелец объект безусловно теряет. Из-за проблемы выше сама конструкция особого смысла не имеет, обобщенный код с ее помощью писать нельзя.

Почему это хуже исключений?

Почему это хуже исключений – отдельный вопрос, о котором я ничего не говорил. Конкретно возврат Result иногда хуже, иногда лучше.

Я говорю о том, почему статические функции хуже конструктора, и почему это многократно усугубляется отсутствием исключений в Расте.

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

Реализуется через замыкания: Foo::with(|| Bar { .. }). На уровне языка, к сожалению, пока еще не гарантируется in-place, но на практике любые копирования выпиливаются в релизе.

И каким образом результат замыкания засунуть в вектор без копирования?

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

С вектором это просто. Если оформить в виде трейта, то вообще будет выглядеть как родной метод.

https://godbolt.org/z/vK84Tq

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

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

С вектором это просто.

Ну это не inplace по сути. Я вообще не вижу отличие между таким подходом и push. Этот пример нужен только если объект создается опционально, типа vec.push_if_empty(|| Bar::new()).

inplace имеется ввиду как placement new, когда мы аллоцируем память сразу в векторе и уже работаем с инициализацией объекта обращаясь к полям которые уже физически лежат в векторе.

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