Rust (язык программирования)

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск
Rust programming language black logo.svg
Семантика:

мультипарадигмальный: параллельное, функциональное, объектно-ориентированное, императивное, структурное программирование

Тип исполнения:

компилируемый

Появился в:

2010

Автор(ы):

Грэйдон Хор, разработчики проекта Rust

Расширение файлов:

.rs

Выпуск:

0.12 (9 октября 2014)[1]

Система типов:

статическая, строгая, с выводом типов, опционально динамическая

Основные реализации:

rustc

Испытал влияние:

Alef, C++, Camlp4, Common Lisp, Erlang, Haskell, Hermes, Limbo, Napier, Napier88, Newsqueak, NIL, Sather, OCaml, Standard ML, Cyclone, Scheme[2]

Повлиял на:

Swift

Лицензия:

лицензия Apache и лицензия MIT

Сайт:

rust-lang.org

ОС:

Linux, OS X, Windows, FreeBSD, iOS и Android

Rust — мультипарадигмальный компилируемый язык программирования общего назначения, разрабатываемый Mozilla Research[3], поддерживающий функциональное программирование, модель акторов, процедурное программирование, объектно-ориентированное программирование.

Основная задача Rust — быть удобным языком для написания больших клиент-серверных приложений, работающих в сети Интернет. Такое позиционирование привело к выбору функциональных возможностей с акцентом на безопасность, контроль за использованием памяти и параллельное выполнение задач. Разработчиками языка ставится задача достичь производительности приложений на Rust сравнимой с производительностью C++-приложений[4]. Rust намеренно не включает в себя каких-то новых и непроверенных идей. Проект нацелен на сбор лучших возможностей из уже существующих языков и решений.

Rust — активно развивающийся язык программирования, новые версии (с добавлением/изменением языковых свойств) выходят примерно раз в 2–3 месяца. После выпуска версии 1.0 планируется перейти к 6-ти недельному циклу выпусков[5].

История[править | править вики-текст]

Работа над языком была начата Грэйдоном Хоаром в 2006 году, в 2009[6] к разработке подключилась Mozilla, и в 2010 году язык был официально представлен на Mozilla Summit 2010[7]. Также в 2010 году разработка языка была переведена с использования компилятора, написанного на OCaml, на компилятор, написанный на Rust, с использованием LLVM в качестве back-end[8]. В следующем году он успешно скомпилировал сам себя[9].

В январе 2012 г. была представлена первая альфа-версия (0.1) компилятора Rust[10].

В апреле 2013 г. вышла версия 0.6. Одновременно с этим, Mozilla объявила о присоединении Samsung к проекту Servo — браузерному движку нового поколения, при активном участии которой код движка Servo был портирован на ARM архитектуру[11].

Обзор[12][править | править вики-текст]

Управление памятью[править | править вики-текст]

В Rust реализована «умная» модель памяти, поддерживающая эффективные структуры данных и безопасные шаблоны параллельного выполнения, а также полностью запрещающая некорректный доступ к памяти, который обычно является источником критических ошибок сегментации в других языках программирования. Отсутствие null-указателей, контроль за использованием не инициализированных и деинициализированных переменных; невозможность совместного использования разделяемых состояний несколькими задачами; статический анализ времени жизни указателей.

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

Управляемые указатели (Rc<T>, Arc<T>)
Указывают на данные, размещенные в куче; несколько управляемых указателей могут адресовать один и тот же объект.
Собственные указатели (Box<T>)
Указывают на данные, размещенные в куче; в одну единицу времени доступ к объекту может адресовать только один указатель.
Ссылки (&T)
Указатели на память, принадлежащую какому-то другому значению. Универсальные указатели, имеющие возможность указывать на любой тип объекта: стековый, размещенный в локальной или обменной куче. В основном используются для написания универсального кода, работающего с данными в функциях, когда тип размещения объекта не важен.
Сырые указатели (*const T)
Указатели без гарантии безопасности. Настоятельно не рекомендуется их использовать.

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

Синтаксис[править | править вики-текст]

Синтаксис Rust похож на Си и C++ с блоками кода, разделёнными фигурными скобками, и такими управляющими ключевыми словами, как if, else, while, и for; комментарии также пишутся в С-формате; имена модулей разделяются двумя символами двоеточия (::).

Ключевое слово let определяет локальную переменную.

Набор операторов в Rust:. Арифметические: * (умножение), / (деление), % (взятие остатка от деления), + (сложение), - (вычитание) и унарный префиксный оператор — для смены знака числа. Как и в С, поддерживаются битовые операторы >>, <<, &, | и ^. Операторы сравнения: ==, !=, <, >, <=, >=. Возможны краткие формы записи логических операторов && (and) и || (or). Для приведения типов в Rust используется бинарный оператор as.

Rust поддерживает макроопределения - относительно простые средства подстановки, выполняющиеся во время этапа подготовки к компиляции (как например, в Си). Макроопределения (макрокоманды) - это определяемые пользователем простые расширения синтаксиса, выполняемые с помощью команды macro_rules! Макрокоманды определяются в том же стиле, что и конструкция сравнения с образцом.

Объектная система[править | править вики-текст]

В Rust объектная система основана на трэйтах (traits) и структурах данных. Трэйты определяют типы, а также соответствующие методы и реализации. Также трэйт может содержать реализациии методов, принимаемые по умолчанию. Реализация обозначается ключевым словом impl.

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

Параллельные вычисления[править | править вики-текст]

Параллельность реализована в виде легковесных «задач», похожих на те, что в Erlang и других языках, поддерживающих модель акторов. При этом задачи обмениваются данными через отправку сообщений, а не используя общую память. Для достижения высокой производительности возможно отправлять данные не через копирование, а используя собственные указатели (Box<T>). Они гарантируют только одного владельца.

Примеры программ[править | править вики-текст]

Примеры являются рабочими при сборке с помощью компилятора Rust от 17 сентября 2014. В то же время, с учётом того, что язык находится в стадии активной разработки, код может не работать в более поздних версиях.

Hello, world!:

fn main() {
    println!("Hello, world!");
}

Поиск факториала, в рекурсивном и итеративном стилях:

// Ветви условия в данной функции демонстрируют необязательный вариант
// неявного возврата значений, что может быть удобно при использовании 
// "функционального" стиля. В отличие от C++ и других родственных языков, 
// в Rust "if" - это выражение, возвращающее значение, а не просто оператор. 
fn fac_recur(n: int) -> int {
    if n <= 1 { 1 }
    else { n * fac_recur(n-1) }
}
 
fn fac_iter(n: int) -> int {
 
    // Переменные объявляются с ключевым словом "let", по умолчанию
    // не изменяемые. Если нужна их изменяемость, добавляется ключевое
    // слово 'mut'.
    let mut i = 1;
    let mut result = 1;
    while i <= n {
        result *= i;
        i += 1;
    }
    return result;    // Пример явно возвращаемого значения.
}
 
fn fac_lambda(n: uint) -> uint {
 
    // Итераторы включают множество методов трансформации.
    // "|accum, x|" - это определение анонимной функции.
    // Оптимизации компиляции преобразуют эту функцию 
    // в нечто, похожее на итеративный вариант.
    range(1, n + 1).fold(1, |accum, x| accum * x)
}
 
fn main() {
    println!("Recursive result: {}", fac_recur(10));
    println!("Iterative result: {}", fac_iter(10));
    println!("Lambda result: {}", fac_lambda(10));
}

Демонстрация возможностей «легковесных» параллельных вычислений в Rust:

// Функция создаёт 10 "задач", которые выполняются параллельно.
// Чтобы убедиться в параллельности, запустите программу несколько раз,
// и обратите внимание на непостоянный порядок вывода результатов.
fn main() {
 
    // Эта строка не изменяемая, поэтому может безопасно использоваться
    // из нескольких "задач".
    let greeting = "Привет";
 
    // Цикл "for" работает с любым типом, реализующим
    // интерфейс (trait) "Iterator".
    for num in range(0i, 10) {
        spawn(proc() {
 
            // "println!" - это статический макрос, выполняющий форматирование
            // строки. Макросы структурные (как в Scheme), а не текстовые (как в Си).
            println!("{:s} из потока номер {:i}", greeting, num);
        });
    }
}

Пример сопоставления с образцом, заимствованного из языков семейства ML:

fn main() {
    let array = ["Arrays", "are", "for", "values", "of", "the", "same", "type"];
    let tuple = ("Tuples", 'r', 4i, 0xDEADBEEFi);
 
    // Выражение "match" - стандартный пример использования сопоставления,
    // аналогичный оператору "switch" из Си или C++.
    let uno = match array {
 
        // Ниже "образец" массива, отражающий синтаксис для массива "array"
        // Нижнее подчёркивание - это образец, обозначающий игнорирование одного
        // элемента. Двоеточие - это образец, обозначающий игнорирование 
        // нескольких элементов.
        [_, _, _, values, ..] => values
    };
 
    // Сопоставление с образцом также может быть использовано при объявлении
    // переменных. Например, далее объявляются 2 новых переменных.
    let (_, dos, _, tres) = tuple;
 
    println!("{:s} {:c} {:x}!", uno, dos, tres);    // Выводит "values r deadbeef!"
}

Сравнение с другими языками[править | править вики-текст]

  • Принципы работы с памятью Rust ощутимо отличаются как от языков с полным доступом к памяти, так и от языков с полным контролем за памятью со стороны GC. Модель памяти Rust построена таким образом, что, с одной стороны, предоставляет разработчику возможность контролировать, где размещать данные, вводя разделение по типам указателей и обеспечивая контроль за их использованием на этапе компиляции. C другой стороны, механизм подсчета ссылок.
  • Rust старается генерировать ошибки компиляции в тех ситуациях, где использование прочих языков приводит к ошибкам времени выполнения (или аварийным завершениям программ).
  • Rust позволяет объявлять функции и блоки кода, как «небезопасные» (unsafe). В области такого небезопасного кода не применяется большинство ограничений, которые как раз и делают Rust безопасным языком.

Примечания[править | править вики-текст]

  1. Rust Release Notes
  2. The Rust Reference Manual#Influences (англ.). Официальный сайт Rust (2014). Проверено 22 сентября 2014.
  3. The Rust Language (англ.). Lambda the Ultimate (8 July 2010). Проверено 30 октября 2010. Архивировано из первоисточника 23 ноября 2012.
  4. Walton, Patrick C++ Design Goals in the Context of Rust (англ.) (5 December 2010). — «… It’s impossible to be “as fast as C” in all cases while remaining safe… C++ allows all sorts of low-level tricks, mostly involving circumventing the type system, that offer practically unlimited avenues for optimization. In practice, though, C++ programmers restrict themselves to a few tools for the vast majority of the code they write, including stack-allocated variables owned by one function and passed by alias, uniquely owned objects (often used with auto_ptr or the C++0x unique_ptr), and reference counting via shared_ptr or COM. One of the goals of Rust’s type system is to support these patterns exactly as C++ does, but to enforce their safe usage. In this way, the goal is to be competitive with the vast majority of idiomatic C++ in performance, while remaining memory-safe…»  Проверено 17 апреля 2012. Архивировано из первоисточника 18 сентября 2012.
  5. Niko Matsakis. Road to Rust 1.0 (англ.). Официальный сайт Rust (15 September 2014). Проверено 22 сентября 2014.
  6. Project FAQ (англ.). Официальный сайт Rust (2014). Проверено 17 апреля 2012.
  7. Brendan Eich. Future Tense (англ.) (29 April 2011). — «At Mozilla Summit 2010, we launched Rust, a new programming language motivated by safety and concurrency for parallel hardware, the “manycore” future which is upon us.»  Проверено 17 апреля 2012. Архивировано из первоисточника 18 сентября 2012.
  8. Graydon Hoare. Rust Progress (англ.) (2 October 2010). Проверено 17 апреля 2012. Архивировано из первоисточника 18 сентября 2012.
  9. Graydon Hoare. [rust-dev] stage1/rustc builds (англ.) (20 April 2011). — «After that last change fixing the logging scope context bug, looks like stage1/rustc builds. Just shy of midnight :)»  Проверено 17 апреля 2012.
  10. Brian Anderson. The Rust compiler 0.1 is unleashed (англ.). Списки рассылки Mozilla (20 January 2012). Проверено 22 сентября 2014.
  11. Brendan Eich. Mozilla and Samsung Collaborate on Next Generation Web Browser Engine (англ.). Официальный блог Mozilla (3 April 2013). Проверено 22 сентября 2014.
  12. The Rust Reference Manual (англ.). Официальный сайт Rust (2014). Проверено 19 сентября 2014.

Литература[править | править вики-текст]

Ссылки[править | править вики-текст]