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

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 21:23, 8 июня 2016.
Rust (язык программирования)
fraimed
Спроектировано Грэйдон Хор, разработчики проекта Rust
Стабильная версия 1.8[1] / 14 апреля 2016 года
Печать дисциплины статическая, строгая, с выводом типов, опционально динамическая
Главная реализация
rustc
Под влиянием
Alef, C++, Camlp4, Common Lisp, Erlang, Haskell, Hermes, Limbo, Napier, Napier88, Newsqueak, NIL, Sather, OCaml, Standard ML, Cyclone, Scheme[2]
Влияние
Swift

Rust —(произносится rʌst) мультипарадигмальный компилируемый язык программирования общего назначения, разрабатываемый Mozilla Research, поддерживающий функциональное программирование, модель акторов, процедурное программирование, объектно-ориентированное программирование.

Язык вырос из личного проекта сотрудника Mozilla Грэйдона Хора. Mozilla начали спонсировать проект в 2009 году и объявили его в 2010 г. Первый релиз компилятора Rust был в январе 2012. Rust 1.0, первый стабильный релиз, был выпущен 15 мая 2015 года. Хотя его развитие финансируется Mozilla, это open-source проект. Язык берет свое название от грибов семейства ржавчины.

Обзор

Цель Rust - стать хорошим языком для создания параллельных и безопасных систем. Это приводит к набору функций с акцентом на безопасность, контроль размещения в памяти и параллелизм. Выполнение безопасного кода, как ожидается, будет медленнее, чем C++. Тем не менее, производительность сравнима с C++, который вручную принимает меры безопасности.

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

Система поддерживает механизм, аналогичный типу классов, называемых "traits", вдохновленный непосредственно языком Haskell. Это средство для обеспечения однорангового полиморфизма достигается путем добавления ограничений на типы объявляемых переменных. Другие особенности от Haskell, такие как высшего многоранговый полиморфизм, пока не поддерживаются.

Синтаксис

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

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

Связанные переменные

Практически всякая программа сложнее 'Hello world' в Rust использует связанные переменные. Они выглядят так:

fn main() {
    let x = 5;
}

Во многих языках они называются просто переменными, но в Rust связанные переменные имеют несколько особенностей. Например, левая сторона let-выражения является паттерном, а не просто именем переменной. Это означает, что мы можем сделать так:

let (x, y) = (1, 2);

Rust является статически типизированным языком, что означает, что мы сначала указываем тип, и он проверяется во время компиляции. Типы указываются после двоеточия (:):

let x: i32 = 5;

Если мы хотим, чтобы связывание было изменяемым, можно использовать слово mut:

let mut x = 5; // mut x: i32
x = 10;

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

Функции

Каждая программа в Rust имеет по крайней мере одну функцию main:

fn main() {
}

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

Функция, которая инкрементирует на единицу целочисленное значение:

fn add_one(x: i32) -> i32 {
    x + 1
}

Функции в Rust возвращают ровно одно значение, тип которого объявляется после "стрелочки", ->. Последняя строка функции определяет, что она возвращает. Обратите внимание на отсутствие ; здесь.

В Rust есть ключевое слово для досрочного входа из функции - return:

fn foo(x: i32) -> i32 {
    return x;

    // we never run this code!
    x + 1
}

Простые типы

Rust имеет ряд типов, которые считаются "простыми". Это означает, что они встроены в язык. Rust структурирован таким образом, что стандартная библиотека также предоставляет ряд полезных типов.

Boolean

Rust имеет встроенный логический тип - bool. Он имеет два значения, истина и ложь:

let x = true;
let y: bool = false;

Char

Тип char представляет собой одно скалярное значение Unicode. Оно создается с помощью символов ' :

let x = 'x';
let two_hearts = '💕';

В отличие от некоторых других языков, символ в Rust является не однобайтовым, а четырехбайтовым.

Численные типы

В Rust есть множество числовых типов нескольких категорий: знаковые и беззнаковые, фиксированные и переменные, с плавающей точкой и целочисленные.

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

Если тип числа не указан явно, он определяется по умолчанию:

let x = 42; // x has type i32
let y = 1.0; // y has type f64

Ниже приведен список различных числовых типов:

  • i8
  • i16
  • i32
  • i64
  • u8
  • u16
  • u32
  • u64
  • isize
  • usize
  • f32
  • f64

Массивы

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

let a = [1, 2, 3]; // a: [i32; 3]
let mut m = [1, 2, 3]; // m: [i32; 3]

Массивы имеют тип [T; N]. N является константой длины массива. Можно получить количество элементов в массив с помощью a.len ():

let a = [1, 2, 3];
println!("a has {} elements", a.len());

Можно получить доступ к определенному элементу массива:

let names = ["Graydon", "Brian", "Niko"]; // names: [&amp;str; 3]
println!("The second name is: {}", names[1]);

Индексы начинаются с нуля, как и в большинстве языков программирования, так что первый элемент [0], а второй [1].

Slice

"Slice" является ссылкой на другую структуру данных. Они полезны для предоставления безопасного, эффективного доступа к части массива без копирования. Например, вы, возможно, захотите, ссылаться на всего одну строку в файл, считываемого в память. По своей природе, slice не создается непосредственно, а только от существующей переменной. Slice имеет свою длину, может быть изменяемым или нет, и во многих отношениях ведет себя как массив:

let a = [0, 1, 2, 3, 4];
let middle = &amp;a[1..4]; // A slice of a: just the elements 1, 2, and 3
let complete = &amp;a[..]; // A slice containing all of the elements in a

Slice имеет тип &[T].

Строки

В Rust тип str - самый примитивный тип строки. Как безразмерный типа, он не очень полезен сам по себе, но становится полезным при размещении за ссылкой, как &str.

Кортежи

Кортеж представляет собой упорядоченный список фиксированного размера:

let x = (1, "hello");

Скобки и запятые формируют этот кортеж. Вот тот же код, но с явно указанными типами:

let x: (i32, &amp;str) = (1, "hello");

Управление памятью

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

В Rust существует несколько типов указателей:

Неизменные (&Т) и изменяемые (&mut T) ссылки

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

Упаковка (Box<T>)

Указатель на данные, размещаемые в куче; за один раз доступа к объекту можно использовать только один указатель.

Управляемые указатели со счетчиком ссылок (Rc <T>) и атомарные ссылки со счетчиком (Arc <T>)

Указатели на данные, размещаемых в куче; несколько указателей могут отсылать к одному и тому же объекту. Arc позволяет получить доступ к разделяемому объекту.

Необрабатываемые указатели неизменяемые (* const Т) и изменяемые (* mut Т)

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

Примеры:

let x = 80;    // связывание владельца x со значением 80
let mut y = 50;    // неизменяемое связывание
let z = &amp;x;    // неизменяемая ссылка на неизменяемое значение
let w = &amp;mut y;    // неизменяемая ссылка на изменяемое значение

*w = 90    // y = 90
*z = 30    // ошибка: попытка изменить через ссылку неизменяемое связывание

let n = Box::new(42);    // упаковка
let m = Rc::new(55);    // счетчик ссылок
let data = Arc::new("test_string")    // атомарная ссылка со счетчиком значений

Объекты системы

В Rust объектная система основывается на признаках и структурах данных. Описание определяет типы и соответствующие методы и реализацию. Описание может включать в себя имплементацию методов по умолчанию. Имплементация обозначена ключевым словом impl.

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

Параллельные вычисления

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

Сравнение с другими языками

  • Принципы памяти Rust существенно отличаются как от языков с полным доступом к памяти, так и от языков со сборщиком мусора. Модель памяти Rust построена таким образом, что, с одной стороны, обеспечивает разработчикам возможность контролировать, куда поместить данные, предоставляя разделение типов индексов и обеспечения контроля за их использованием во время компиляции. А с другой стороны, есть механизм подсчета ссылок.
  • Rust выдает ошибки компиляции в тех случаях, в которых использование других языков приводит к ошибке времени исполнения или сбою программы.
  • Rust позволяет объявлять функции и блоки кода, как "небезопасные". В области такого небезопасного кода не применяются большинство ограничений, которые делают Rust безопасным языком.

Список литературы

  1. Rust documentation
  2. The Rust Programming Language
    1. "Rust Releases". 
    2. "The Rust Reference Manual#Influences". Официальный сайт Rust. 2014. Retrieved 2014-09-22.