Сегодня завершаются циклы стабильного Rust 1.2 и бета-Rust 1.3! Читайте дальше об основных изменениях или переходите к более подробным release notes.

Что вошло в стабильный релиз 1.2


Как сообщалось ранее, Rust 1.2 принёс два существенных улучшения в компиляторе:

  • Общее повышение производительности компилятора, что наиболее заметно в пакетах hyper (компилируется в 1.16 раза быстрее), html5ever (в 1.62 раза), regex (в 1.32 раза) и rust-encoding (в 1.35 раза). Вы можете посмотреть подробную статистику производительности на этом сайте (сделанном Nick'ом Cameron'ом), выставив даты с 2015-05-15 по 2015-06-25.
  • Параллельная кодогенерация теперь работает и даёт прирост в 33% скорости на начальных стадиях компиляции компилятора Rust на четырёхъядерной машине. Параллельная кодогенерация особенно полезна для отладочных сборок, потому что она предотвращает использование некоторых оптимизаций; но она также может использоваться и при включённых оптимизациях, давая, по факту, уровень -O1. Активировать параллельную генерацию можно, передав rustc флаг -C codegen-units=N, где N — желаемое количество параллельных потоков.

Производительность Cargo также существенно улучшилась:

  • Сборки, которые не требуют перекомпиляций («no-op-сборки») в больших проектах стали гораздо быстрее; например, в Servo время сборки упало с 5 секунд до 0.5 секунды.
  • Cargo теперь поддерживает разделяемые «целевые» директории, в которых кешируются скомпилированные зависимости для разных пакетов, что значительно уменьшает время сборки в сложных проектах.

Также в релиз 1.2 вошла поддержка тулчейна MSVC (Microsoft Visual C), в дополнение к вариантам от GNU. В итоге, код на Rust теперь может напрямую линковаться с кодом, собранным нативными для Windows утилитами. Сам компилятор способен bootstrap'иться на MSVC, у нас уже есть предварительные ночные сборки, и мы тестируем все библиотеки rust-lang на MSVC. Поддержки раскрутки стека (unwinding) ещё нет (процесс завершается при паниках), но работа над её внедрением ведётся.

С точки зрения языка, в Rust 1.2 завершилась работа над поддержкой типов с динамическим размером, что дало возможность умным указателям вроде Rc напрямую работать с массивами и трейт-объектами, т.е., например, Rc<[T]> полностью готов к использованию. Это улучшение применимо ко всем умным указателям из стандартной библиотеки. Поддержка для сторонних типов указателей доступна в ночных сборках и вскоре будет стабилизирована полностью.

Что нового в 1.3 beta


Одной из наиболее интересных разработок в цикле 1.3 было создание Растономикона — новой книги о «тёмных искусствах продвинутого и небезопасного программирования на Rust». Пока что эта книга только в самом начале написания, но уже сейчас в ней есть совершенно бесценное описание более тонких аспектов Rust.

В цикле 1.3 также имеются улучшения производительности, в основном, в стандартной библиотеке:


Мы также предприняли отдельные шаги к предварительной поддержке Windows XP. Хоть мы и не собираемся делать Windows XP платформой «первого класса», теперь стало возможным программировать на Rust под XP, если избегать использования отдельных элементов стандартной библиотеки.

Со стороны Cargo мы добавили возможность ограничения lint'ов, согласно ранее принятому RFC. Идея этой функциональности в том, что lint'ы зависимостей вашего проекта не должны мешать вам скомпилировать проект, что, в свою очередь, даст нам возможность подстраивать поведение lint'ов, не оказывая негативного влияния на экосистему в целом.

Контрибьюторы релиза 1.2


Стабильный релиз 1.2 является плодом упорной работы 180 человек:

список
Aaron Turon
Abhishek Chanda
Adolfo Ochagavia
Aidan Hobson Sayers
Akshay Chiwhane
Alex Burka
Alex Crichton
Alex Stokes
Alexander Artemenko
Alexis Beingessner
Andrea Canciani
Andrew Foote
Andrew Kensler
Andrew Straw
Ariel Ben-Yehuda
Austin Hellyer
Barosl Lee
Ben Striegel
Bjorn Steinbrink
Brian Anderson
Brian Campbell
Brian Leibig
Brian Quinlan
Carol (Nichols || Goulding)
Chris Hellmuth
Christian Stadelmann
Chuck Bassett
Corey Farwell
Cornel Punga
Cruz Julian Bishop
Dave Huseby
David Campbell
David Stygstra
David Voit
Eduard Bopp
Eduard Burtescu
Eli Friedman
Emilio Cobos Alvarez
Emily Dunham
Eric Ye
Erik Michaels-Ober
Falco Hirschenberger
Felix S. Klock II
FuGangqiang
Geoffrey Thomas
Gleb Kozyrev
Guillaume Gomez
Gulshan Singh
Heejong Ahn
Huachao Huang
Huon Wilson
Ivan Ukhov
Iven Hsu
Jake Goulding
Jake Hickey
James Miller
Jared Roesch
Jeremy Schlatter
Jexell
Jim Blandy
Johann Tuffe
Johannes Hoff
Johannes Oertel
John Hodge
Jonathan Reem
Joshua Landau
Kevin Ballard
Kubilay Kocak
Lee Jeffery
Leo Correa
Liigo Zhuang
Lorenz
Luca Bruno
Luqman Aden
Manish Goregaokar
Marcel Muller
Marcus Klaas
Marin Atanasov Nikolov
Markus Westerlind
Martin Pool
Marvin Lobel
Matej Lach
Mathieu David
Matt Brubeck
Matthew Astley
Max Jacobson
Maximilian Haack
Michael Layzell
Michael Macias
Michael Rosenberg
Michael Sproul
Michael Woerister
Mihnea Dobrescu-Balaur
Mikhail Zabaluev
Mohammed Attia
Ms2ger
Murarth
Mario Feroldi
Nathan Long
Nathaniel Theis
Nick Cameron
Nick Desaulniers
Nick Fitzgerald
Nick Hamann
Nick Howell
Niko Matsakis
Nils Liberg
OlegTsyba
Oliver ‘ker’ Schneider
Oliver Schneider
P1start
Parker Moore
Pascal Hertleif
Paul Faria
Paul Oliver
Peer Aramillo Irizar
Peter Atashian
Peter Elmers
Philip Munksgaard
Ralph Giles
Rein Henrichs
Ricardo Martins
Richo Healey
Ricky Taylor
Russell Johnston
Russell McClellan
Ryan Pendleton
Ryman
Remi Audebert
Sae-bom Kim
Sean Collins
Sean Gillespie
Sean Patrick Santos
Seo Sanghyeon
Simon Sapin
Simonas Kazlauskas
Steve Gury
Steve Klabnik
Steven Allen
Steven Fackler
Steven Walter
Sebastien Marie
Tamir Duberstein
Thomas Karpiniec
Tim Ringenbach
Tshepang Lekhonkhobe
Ulrik Sverdrup
Vadim Petrochenkov
Wei-Ming Yang
Wesley Wiser
Wilfred Hughes
Will Andrews
Will Engler
Xuefeng Wu
XuefengWu
Yongqian Li
York Xiang
Z1
ben fleis
benaryorg
bluss
bors
clatour
diwic
dmgawel
econoplas
frankamp
funkill
inrustwetrust
joliv
klutzy
marcell
mdinger
olombard
peferron
ray glover
saml
simplex
sumito3478
webmobster

Комментарии (12)


  1. evgenymarkov
    08.08.2015 21:18
    +3

    Отличная новость, больше тулчейнов хороших и разных для хорошего языка! А пока есть небольшая проблема с компиляцией rustc для ARM: для сборки используется помимо g++ некий snapshot, а он предоставляется только для x86 архитектур. Может кто-то подсказать как это обойти? Я в курсе, что официально пока что поддерживаются только x86, но кого это когда-то останавливало?)
    В гугле удалось найти только про кросскомпиляцию программ с использованием --target и указанием различных тулчейнов.


    1. stepik777
      09.08.2015 10:17

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


  1. NeoCode
    08.08.2015 23:30
    +1

    А можно подробнее узнать про «типы с динамическим размером»? Что это такое, в чем особенности реализации, какие задачи решают и т.д.
    Я так понимаю это не то же самое что обычные динамические структуры данных вроде списков и векторов?


    1. IRainman
      09.08.2015 07:08
      -2

      У меня ощущение, что это подразумевается своеобразный полиморфизм этапа выполнения, когда структура (декларация) класса могут меняться в процессе работы, соответственно и размер объектов будет меняться. Меняется размер, наверняка, с помощью какого нибудь метода «эволюция» или нечто подобного.


    1. stepik777
      09.08.2015 10:35
      +3

      Это типы, размер которых неизвестен на этапе компиляции, их нельзя использовать напрямую, можно пользоваться только ссылками на них.
      На сколько я знаю, есть 2 вида таких типов:
      1. Слайс (slice, в этой статье они называются срезами) — это часть массива или вектора, обозначается [T].
      2. Трейт-объект (trait-object) — любой объект, реализующий данный трейт (интерфейс). Аналог в С++ — абстрактные классы, нельзя использовать абстрактный класс, можно использовать только указатель на него.

      Особенность ссылок на эти объекты, в том, что они состоят из двух частей — указателя на сам объект и некоей дополнительной информации. В случае со слайсом этой дополнительной информацией будет размер слайса или указатель на его конец (я не знаю деталей реализации), а в случае с трейт-объектом — это указатель на таблицу методов (аналог vtable в C++).


      1. NeoCode
        09.08.2015 17:18
        +1

        А что следует понимать под «размером типа»? Размер объекта этого типа или что-то другое?
        Можно ли сказать, что в C++ размер объектов std::vector, std::list и т.п. также неизвестен во время компиляции? (я бы так сказал, но вдруг в терминах Rust под этим понимается что-то другое...)
        Если да — то что нового привнес Rust в работу с такими динамическими структурами данных, по сравнению с тем же С++?


        1. stepik777
          09.08.2015 18:58

          Да, я имел в виду размер объекта этого типа.
          Размер std::vector — это то, что возвращает sizeof, то есть размер нескольких указателей, это не тип динамического размера.

          Например тип u32 — это тип со статическим размером, переменная типа u32 имеет размер 4 байта, а переменная типа &u32 (ссылка на u32) — 4 или 8 байт, в зависимости от архитектуры.
          Если вам нужно сослаться на область памяти, где последовательно хранятся 32-битные числа (например кусок вектора или массива), то можно использовать &[u32], эта ссылка имеет фиксированный размер, в то же время размер [u32] может быть произвольным.

          Если вам нужно сослаться на область памяти в С++, вы можете создать структуру вида:

          template<typename T>
          struct slice {
              T* begin;
              size_t size;
          }
          
          Это будет тоже самое, что &[u32] в Расте, но выразить сам тип [u32] в C++ нельзя.


          1. NeoCode
            09.08.2015 19:21

            Ну хорошо, в случае std::vector там тоже где-то будет указатель на начало и дополнительная информация — указатель на последний элемент, на конец буфера и еще что-то. В случае std::list — указатель на начало и дополнительная информация — указатель на следующий элемент списка.
            Все-же как-то все очень непонятно, что именно они там с этими «типами с динамическим размером» сделали.


            1. Googolplex
              10.08.2015 00:46
              +3

              stepik777 всё правильно объясняет.

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

              С другой стороны, существуют типы, размер которых на этапе компиляции неизвестен точно. Например, это «абстрактный» массив — т.е. некоторая последовательность элементов одного типа, но с неизвестной длиной. Другой пример — тип, объединяющий все типы, реализующие какой-нибудь трейт. Например, если Display — это трейт, то Display в контексте типа обозначает любой тип, реализующий этот трейт. Понятно, что потенциально любой тип может реализовывать трейт, поэтому размер таких «объединяющих» типов тоже неизвестен.

              Типы с неизвестным размером можно использовать только при выполнении двух условий:

              1. доступ к их объектам осуществляется только через указатель;
              2. вместе с указателем должна храниться какая-то дополнительная информация, позволяющая «обойти» статическое незнание конкретики о типе.


              Первое условие нужно, потому что вы не можете использовать объекты типа с неизвестным размером по значению — для этого компилятору придётся выделить память на стеке, но как её выделить, если нужный размер неизвестен? Размер же указателя известен всегда.

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

              Например, возьмём тип &[i32] — срез i32. Это ссылка на тип с динамическим размером [i32]. Обычно ссылки реализуются в виде указателей, например, &i32 на самом низком уровне представляется в виде одного 8-байтного или 4-байтного числа. Но &[i32] — это толстый указатель, и он состоит из двух чисел: указателя на начало массива и длины этого массива. При создании &[i32], т.е. при взятии ссыли на массив и преобразовании её в срез, информация о длине исходного массива сохраняется внутри толстого указателя.

              &Display — это трейт-объект для трейта Display. В переменной такого типа может храниться указатель на любой тип, который реализует трейт Display. Однако для того, чтобы такую переменную можно было бы использовать, нужно вместе с указателем на значение хранить ссылку на таблицу методов Display, которые реализует тип, значение которого лежит в этой переменной. Поэтому &Display — это толстый указатель, который состоит из указателя на значение и указателя на таблицу виртуальных методов для типа этого значения. При создании ссылки на объект и преобразовании её в трейт-объект указатель на таблицу виртуальных методов сохраняется внутри толстого указателя.

              В модуле std::raw лежат структуры, описывающие толстые указатели для разных видов DST. Эти типы можно напрямую преобразовывать (с помощью mem::transmute(), аналога reinterpret_cast из C++) в ссылки на типы с динамическим размером, т.е., например, можно преобразовать std::raw::Slice в &[i32] и наоборот.

              Что касается изменений именно в данном релизе, то теперь можно сказать, что типы с динамическим размером поддерживаются компилятором (практически) в полном объёме. Например, можно создавать умные указатели, аналогичные Box из стандартной библиотеки, которые будут прозрачно работать с DST, т.е. автоматически становиться толстыми указателями, если они используются для DST. Раньше этого было сделать нельзя.


              1. NeoCode
                10.08.2015 15:00

                То есть по сути это «толстые указатели» — на самом деле обычные структуры/классы, которые ведут себя как указатели и содержат дополнительную информацию? Некий аналог умных указателей С++, с какой-то поддержкой со стороны компилятора?
                Может ли программист придумать свой DST? Будет ли компилятор понимать что это «DST» и работать с ним тем особым образом, как он работает со встроенными?


                1. Googolplex
                  10.08.2015 16:24
                  +1

                  Это не совсем «обычные структуры/классы», знание о них заложено в компилятор. Например, в случае с трейт-объектами это не обойти никак, потому что в трейт-объектах дополнительная информация — это указатель на vtable, который знает только компилятор. Я думаю, что, теоретически, срезы, которые содержат дополнительную информацию о длине, можно было бы реализовать в сторонней библиотеке, но на данный момент срезы также встроены в язык. То, что лежит в std::raw — это совместимое представление толстых указателей в виде структур, но это не значит, что эти структуры на самом деле используются.

                  Да, программист может определять свои DST. Например, Path и CStr из стандартной библиотеки — это типы с динамическим размером. Однако на данный момент возможности по созданию DST сильно ограничены, и их реализация не очень, скажем так, приятна глазу. По факту, можно создавать и использовать срезоподобные DST (как вышеописанные Path и CStr). Возможно, можно как-то заюзать этот механизм для сохранения собственной информации. Чего-то большего пока что сделать нельзя, например, нельзя как-то описать толстый указатель с дополнительной информацией в виде собственной структуры, но, я думаю, кто-нибудь может написать RFC по этому поводу, и, возможно, что-то такое будет в будущем добавлено в язык. Пока что, насколько я понимаю, особой необходимости в этом нет.


  1. vsb
    09.08.2015 07:33

    Простейший пример типа с динамическим размером: [T] это массив неизвестного (на этапе компиляции) размера.