Выпуск Rust 1.41.0: новые гарантии для Box<T> в FFI, улучшения в cargo install, ослабление ограничений для типажей

Original author: The Rust Release Team
  • Translation

Команда Rust рада сообщить о выпуске новой версии, 1.41.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.


Если вы установили предыдущую версию Rust средствами rustup, то для обновления до версии 1.41.0 вам достаточно выполнить следующую команду:


rustup update stable

Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.


Что вошло в стабильную версию 1.41.0


Основными новшествами Rust 1.41.0 являются ослабление ограничений на реализацию типажей, улучшения cargo install, новый формат файла Cargo.lock более дружелюбный для работы с git, и новые гарантии для Box<T>, связанные с FFI. Смотрите подробности выпуска для дополнительной информации.


Ослабление ограничений при реализации типажей


Для предотвращения поломок в экосистеме, когда зависимость добавляет новые реализации типажа, Rust использует правило сироты (orphan rule). Суть в том, что реализация типажа допустима только если типаж или тип, который его реализует, является локальным, т.е. определённым в текущем крейте. Однако это достаточно сложно, когда используются обобщения.


До версии Rust 1.41.0 это правило было слишком строгим, мешая композиции. Например, предположим что ваш пакет реализует структуру BetterVec<T>, и вы хотите иметь возможность конвертации его в Vec<T> из стандартной библиотеки. Вы бы написали следующий код:


impl<T> From<BetterVec<T>> for Vec<T> {
    // ...
}

… который является примером паттерна:


impl<T> ForeignTrait<LocalType> for ForeignType<T> {
    // ...
}

В версии Rust 1.40.0 этот impl был запрещён правилом сироты, так как From и Vec определены в стандартной библиотеке, которая является чужим крейтом по отношению к текущему крейту. Были способы обойти это ограничение, такие как шаблон newtype, но они часто были громоздкими или даже невозможными в некоторых случаях.


Хотя From и Vec всё ещё остаются чужими, типаж (в данном случае From) параметризован локальным типом. Поэтому, Rust 1.41.0 позволяет этот impl.


Для более подробной информации читайте отчёт о стабилизации и предложение RFC.


cargo install обновляет пакеты если они устарели


При помощи cargo install вы можете установить в систему исполняемый крейт. Эта команда часто используется для установки популярных CLI-инструментов, созданных комьюнити и написанных на Rust.


Начиная с Rust 1.41.0, cargo install также может обновлять установленные крейты, если с момента установки появился новый релиз. До этого выпуска единственным возможным вариантом было использование флага --force, который позволял переустановить исполняемый крейт даже если он не нуждался в обновлении.


Менее конфликтный формат Cargo.lock


Для обеспечения консистентных сборок, Cargo использует файл с названием Cargo.lock, который содержит версии зависимостей и контрольные суммы. К сожалению, формат организации данных в нём мог привести к ненужным конфликтам слияния при изменении зависимостей в отдельных ветках.


Rust 1.41.0 представляет новый формат для этого файла, разработанный специально для уменьшения конфликтов. Новый формат будет использоваться для всех новых lock-файлов, в то время как существующие файлы будут использовать предыдущий формат. Узнать больше о вариантах, которые привели к новому формату, вы можете в PR, в котором его добавили.


Больше гарантий при использовании Box<T> в FFI


Начиная с Rust 1.41.0, мы заявляем, что Box<T>, когда T: Sized, теперь совместим по ABI с типами указателей в C (T*). Таким образом, если вы определяете функцию extern "C" в Rust и вызываете её из C, ваша функция в Rust теперь может использовать Box<T> для какого-то T, и использовать T* в соответствующей функции на C. В качестве примера, на стороне C вы можете иметь:


// C header */

// Возвращаем владение в вызывающий код
struct Foo* foo_new(void);

// Принимает владение из вызывающего кода; no-op если передан NULL.
void foo_delete(struct Foo*);

… а на стороне Rust у вас будет:


#[repr(C)]
pub struct Foo;

#[no_mangle]
pub extern "C" fn foo_new() -> Box<Foo> {
    Box::new(Foo)
}

// Возможность принимать NULL реализуется с помощью `Option<_>`.
#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}

Заметим однако, что несмотря на то, что Box<T> и T* имеют одинаковое представление и ABI, Box<T> обязательно должен быть не-null, выровнен и быть готовым для деаллокации глобальным аллокатором. Чтобы обеспечить эти требования, самое лучшее — это использовать такие Box'ы, которые порождаются глобальным аллокатором.


Важно: По крайней мере в настоящее время вы должны избегать использования типов Box<T> для функций, которые определены в C, но вызываются из Rust. В этих случаях вы должны отразить типы как можно ближе к определению в C. Использование типов наподобие Box<T>, когда определение в C использует просто T* может привести к неопределённому поведению.


Чтобы узнать больше, обратитесь к документации Box<T>.


Изменения в библиотеке


В версии Rust 1.41.0, мы сделали следующие изменения в стандартной библиотеке:



Сокращение поддержки 32-битной целевой платформы Apple


Rust 1.41.0 будет последним выпуском с текущим уровнем поддержки 32-битных платформ Apple, включая i686-apple-darwin. Начиная с Rust 1.42.0 эти платформы будут понижены до самого низкого уровня поддержки.


Узнать об этом больше вы можете в соответствующей записи в блоге.


Другие изменения


Синтаксис, пакетный менеджер Cargo и анализатор Clippy также претерпели некоторые изменения. Мы также приступили к внедрению оптимизаций MIR, которые должны ускорить компиляцию: вы можете узнать о них в блоге "Inside Rust".


Участники 1.41.0


Множество людей собрались вместе, чтобы создать Rust 1.41.0. Мы не смогли бы сделать это без всех вас, спасибо!


От переводчиков


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


Данную статью совместными усилиями перевели andreevlex, blandger, funkill, P0lunin и nlinker.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 15

    +18

    В официальном посте почему-то про это не написали, но 1.41 наконец-то стабилизировал очень ожидаемую многими разработчиками чего-то интерактивного штуку: "profile overrides". TLDR: позволяет выборочно использовать разные профили сборки для основного кода и зависимостей.


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


    # Set the default for dependencies.
    [profile.dev.package."*"]
    opt-level = 2

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


    Еще оно может быть полезно, например, для выключения оптимизаций для build-time зависимостей (типа syn), что для некоторых проектов может чуть ли не в два раза уменьшить время полной release сборки.

      0

      О да, крайне полезная фича когда нужно крутить небольшой кусок кода сути в dev profile, а остальное эффективно в release.


      Также крайне приятно, что в этом релизе таки заехали ослабленные orphan rules, раньше это было несколько болезненно.

      +1
      К сожалению, формат организации данных в нём мог привести к ненужным конфликтам слияния при изменении зависимостей в отдельных ветках.

      Теперь новый формат может приводить к интересным проблемам после успешного слияния :D

        0

        Кириллические имена переменных и функций до сих пор не поддерживаются? :(? Их поддержку в принципе собираются делать ?

          +3
          Простите за вопрос, но неужели подобное действительно где-то используется? Ведь таким макаром недолго докатиться и до…

          文言文編程語言
          image
            0
            а чего бы нет? Как хочу, так и называю. 21 век на дворе.
              +4
              Ну вот представьте, что к вам на поддержку придет код, где все идентификаторы записаны иероглифами или деванагари.
                0

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


                Если же вы сейчас скажете, что я могу и не суметь перевести названия правильно — то ведь и автор кода совершенно не обязательно сможет это сделать!

                  0
                  Да хоть эмодзи. Если это делается то это делается с какой-то определённой целью (образовательной, развлекательной, etc).
                –6

                Практически везде в прикладной сфере, Врятли БД/EPR/CRM магазина, склада или ещё чегото подобного будут передавать на аутсорсинг индусам или продавать гуглу. а понимаемость кода сильно увеличивается. Если конечно не брать дебильные примеры когда в первом коментет предлагают писать сортировку пузырьком на старославянском или удаффкомовском и всё обсуждение сводится к стёбу.


                1. вот пример полной русификации по умному — путём добавления синонимов русификации Lua для того чтобы прикрутить его к QUIK https://тхаб.рф/wiki/LuaRu — используется для написания торговых роботов, сейчас я использую Эксел но все переменные и функции там по русски — цена ошибки слишком высока (в финансовом плане)
                2. Вот код на питоне для обучения ребёнка программированию и физике — я показал его ребёнку 14 лет и она сразу всё поняла как работает код, что такое функция и переменная — 10 минут !!!

                -------------------------------------------------------------------------------
                Name: Физика.Теплотп.Вода
                Purpose: Темплоёмкость, тепелота палвления и испарения воды
                Author: Максим
                Created: 23.10.2019
                -------------------------------------------------------------------------------
                модульный тест utest_ТеплоёмкостьВоды.py

                """ Свойства воды воды"""


                ТеплоёмкостьЛьда = 2060 # при = 0 С, Дж/градускГ
                ТеплоёмкостьПара = 2200 # при = 0 С, Дж/градус
                кГ


                ТеплоёмкостьВоды = 4200 # при = 0 С, Дж/градускГ
                ТеплоёмкостьВоды0 = 4218 # при = 0 С, Дж/градус
                кГ
                ТеплоёмкостьВоды10 = 4192 # при = 10 С, Дж/градускГ
                ТеплоёмкостьВоды20 = 4182 # при = 20 С, Дж/градус
                кГ
                ТеплоёмкостьВоды40 = 4178 # при = 40 С, Дж/градускГ
                ТеплоёмкостьВоды60 = 4184 # при = 60 С, Дж/градус
                кГ
                ТеплоёмкостьВоды80 = 4196 # при = 80 С, Дж/градускГ
                ТеплоёмкостьВоды100 = 4216 # при = 100 С, Дж/градус
                кГ


                УдельнаяТеплотаПалавленияЛьда = 340000 # Дж/кГ
                УдельнаяТеплотаПарообразования = 2256000 # Дж/кГ


                def функцияНагревЛьда(МассаЛьда, ТемператураНачальная, ТемператураКонечная):


                """ Функция расчёта теплоты необходимой для нагрева льда """
                
                if ТемператураНачальная < 0 and ТемператураКонечная < 0 :
                    if ТемператураКонечная > 0 : ТемператураКонечная = 0
                    # print ("ТемператураКонечная = ", ТемператураКонечная)
                    ТеплотаНагреваЛьда = МассаЛьда * ТеплоёмкостьЛьда * (ТемператураКонечная-ТемператураНачальная)
                
                print("Теплота на нагрев Льда", ТеплотаНагреваЛьда / 1000, "кДж")
                return ТеплотаНагреваЛьда

                def функцияПлавлениеЛьда(МассаЛьда):
                ТеплотаПлавленияЛьда = 0
                if ТемператураНачальная <= 0 and ТемператураКонечная <= 0:
                ТеплотаПлавленияЛьда = МассаЛьда * УдельнаяТеплотаПалавленияЛьда
                print("Теплота на Плавление Льда = ", ТеплотаПлавленияЛьда / 1000, "кДж")
                return ТеплотаПлавленияЛьда


                def функцияИспарениеВоды(МассаВоды):
                if ТемператураНачальная < 0 and ТемператураКонечная < 0:
                ТеплотаИспаренияВоды = МассаВоды * УдельнаяТеплотаПарообразования
                print("Теплота на Испарение Воды", ТеплотаИспаренияВоды / 1000, "кДж")
                return ТеплотаИспаренияВоды


                def функцияНагревВоды(МассаВоды, ТемператураНачальная, ТемператураКонечная):
                if ТемператураНачальная < 0: ТемператураНачальная = 0
                if ТемператураКонечная > 100: ТемператураКонечная = 100
                ТеплотаНаргеваВоды = МассаВоды ТеплоёмкостьВоды (ТемператураКонечная-ТемператураНачальная)
                print("Теплота на Нагрев Воды =", ТеплотаНаргеваВоды / 1000, "кДж")
                return ТеплотаНаргеваВоды


                def функцияНагревПара(МассаПара, ТемператураНачальная, ТемператураКонечная):
                if ТемператураНачальная < 100: ТемператураНачальная = 100
                ТеплотаНаргеваПара = МассаПара ТеплоёмкостьПара (ТемператураКонечная-ТемператураНачальная)
                print("Теплота на Нагрев Пара =", ТеплотаНаргеваПара / 1000, "кДж")
                return ТеплотаНаргеваПара


                def формулаТепло(Масса, ТемператураНачальная, ТемператураКонечная):


                Если лёд нагревается но не плавится
                if (ТемператураНачальная < 0 and  ТемператураКонечная < 0 ):
                    ТеплоДж = функцияНагревЛьда(Масса, ТемператураНачальная, ТемператураКонечная)
                # Если лёд нагреватеся, плавится, и нагревается вода, но не испаряется
                if (ТемператураНачальная <= 0 and 0 <= ТемператураКонечная < 100 ):
                    # Температура  = 0
                    ТеплоДж = функцияНагревЛьда(Масса, ТемператураНачальная, ТемператураКонечная) + функцияПлавлениеЛьда(Масса) + функцияНагревВоды(Масса, ТемператураНачальная, ТемператураКонечная)
                # Если лёд нагреватеся, плавится, и нагревается вода, но не испаряется
                if (ТемператураНачальная <= 0 and ТемператураКонечная > 100 ):
                    # Если лёд нагреватеся, плавится, и нагревается вода, а потом испаряется
                    ТеплоДж = функцияНагревЛьда(Масса, ТемператураНачальная, 0) + функцияПлавлениеЛьда(Масса) + функцияНагревВоды(Масса, 0, 100) + функцияИспарениеВоды(Масса) + функцияНагревПара(Масса, 0, ТемператураКонечная)
                # Если вода только нагревается но не испаряется
                if (ТемператураНачальная > 0 and  ТемператураКонечная < 100 ):
                    ТеплоДж = функцияНагревВоды(Масса, ТемператураНачальная, ТемператураКонечная)
                # Нагреватеся только пар
                if (ТемператураНачальная > 100 and  ТемператураКонечная > 100 ):
                    ТеплоДж = функцияНагревПара(Масса, ТемператураНачальная, ТемператураКонечная)
                
                return ТеплоДж

                def формулаТепло2(Масса, ТемператураНачальная, ТемператураКонечная):


                Тепло
                ТеплоНагреваЛьда = функцияНагревЛьда(Масса, ТемператураНачальная, ТемператураКонечная)
                # Если лёд плавится
                ТеплоПлавленияЛьда = функцияПлавлениеЛьда(Масса)
                # Если лёд нагреватеся, плавится, и нагревается вода, но не испаряется
                ТеплоНагреваВоды = функцияНагревВоды(Масса, ТемператураНачальная, ТемператураКонечная)
                
                # Если лёд нагреватеся, плавится, и нагревается вода, но не испаряется
                ТеплоИспаренияВоды = функцияИспарениеВоды(Масса)
                
                # Нагреватеся только пар
                ТеплоНагреваПара = функцияНагревПара(Масса, ТемператураНачальная, ТемператураКонечная)
                ТеплоДжоули = ТеплоНагреваЛьда + ТеплоПлавленияЛьда + ТеплоНагреваВоды + ТеплоИспаренияВоды
                
                return ТеплоДжоули

                print("ИТОГО: Теплота необходимая для нагрева: ", формулаТепло(1, 1, 99 ), " кДж")


                PS Есть идея добавить русские синонимы операторов в язык Питон чтобы он и оригинальный код понимал и по русски можно было школьникам всякие сложные парадигмы программирования объяснять типа ООП и функционального программирования. вместо богомерзкого Кумира и рисования черепашкой по клеточкам. Если кто может оказать помощь хотя бы консультацией пишите в личку.

                  +2

                  Вас не волнует, что операторы и названия в сторонних библиотеках будут всё равно на английском и код превратится в кашу из русских и английских символов? А теперь представьте, что авторы всех библиотек на питоне начнут писать их на своих языках, включая иероглифы и прочую радость. Это будет ад (особенно если они ещё и управляющие слова типа if, for, def и т.п. переименуют на свои)

                    0
                    1. каши нет наоборот удобно — очень легко различать свой код и чужой.
                    2. Лечится написанием простого плагина для MS Visual Studio Code Рус-Лат
                    3. программисты не идиоты… тиам где удобнее будут писать хоть на идиш, если хотят поддержки сообщества, продать или распространения перепишут на английский, плагинов для массового корректного переименования переменных полно.
                      +2
                      программисты не идиоты… тиам где удобнее будут писать хоть на идиш, если хотят поддержки сообщества


                      Я бы не был столь уверен. Приходилось как-то разбираться в коде проекта, разработанного китайскими коллегами, так там большая часть строковых констант типа названий файлов/директорий была ни китайском. Например, файл конфига там назывался что-то вроде 配置.ini. Все комментарии тоже на китайском, разумеется. При этом продукт был не сугубо для внутреннего китайского рынка. Даже думать не хочу, что бы там творилось, если бы им дали возможность еще и переменные и функции на китайском называть.
                    –1
                    camelCase в питоне, знаете толк в изврашщениях, думаю подчёркивание и изобрели чтобы заменить проблем такм где его ставить нельзя по чисто техзническими причинам, заче склеивать несколько слов в одно?
                  +2

                  Мой прошлый ответ все еще актуален: "Пока нет. За прогрессом можно следить тут: https://github.com/rust-lang/rust/issues/55467"


                  Их поддержку в принципе собираются делать ?

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

                Only users with full accounts can post comments. Log in, please.