Русская Википедия:Rust (язык программирования)

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Шаблон:Другие значения Шаблон:Карточка языка программирования Rust (Раст, Шаблон:МФА2; Шаблон:Tr-en) — мультипарадигменный компилируемый язык программирования общего назначения, сочетающий парадигмы функционального и процедурного программирования с объектной системой, основанной на типажах. Управление памятью осуществляется через механизм «владения» с использованием Шаблон:Нп5[1], что позволяет обходиться без системы сборки мусора во время исполнения программы. Rust гарантирует безопасную работу с памятью благодаря встроенной в компилятор системе статической проверки ссылок (Шаблон:Lang-en2). Имеются средства, позволяющие использовать приёмы объектно-ориентированного программирования[2].

Ключевые приоритеты языка: безопасность, скорость и параллелизм. Rust пригоден для системного программирования, в частности, он рассматривается как перспективный язык для разработки ядер операционных систем[1]. Rust сопоставим по скорости и возможностям с C++/Си, однако даёт большую безопасность при работе с памятью, что обеспечивается встроенными в язык механизмами контроля ссылок. Производительности программ на Rust способствует использование «абстракций с нулевой стоимостью»[3].

После нескольких лет активной разработки первая стабильная версия (1.0) вышла 15 мая 2015 года, после чего новые версии выходят раз в 6 недель[4]. Для версий языка, вышедших после 1.0, заявлена обратная совместимость[5].

Разрабатывается с 2010-х годов сообществом Mozilla Research и финансируется фондом Mozilla Foundation. С 2020 года планировалась передача интеллектуальной собственности и процессов развития и финансирования языка в организацию Rust Foundation[6]. 8 февраля 2021 года пять компаний-учредителей (AWS, Huawei, Google, Microsoft и Mozilla) официально объявили о создании Rust Foundation.[7][8]

Семь лет подряд с 2016 по 2022 год Rust занимает первое место в списке самых любимых языков программирования («Most loved programming languages») по версии ежегодного опроса разработчиков Stack Overflow Developer Survey[9][10][11][12].

История

Работа над языком была начата сотрудником Mozilla Грэйдоном Хором в 2006 году. Автор дал проекту название Rust, по его словам, связанное с грибами семейства ржавчинные (Шаблон:Lang-en)[13].

В 2009 году[14] компания Mozilla начала отдельно спонсировать разработку Rust. Спустя год язык был официально представлен на Mozilla Summit 2010[15]. Изначальный компилятор, реализованный на OCaml, был заменён на новый, написанный на Rust и использующий LLVM для генерации машинного кода[16]; в следующем году новый компилятор впервые успешно скомпилировал сам себя[17].

Первая официальная альфа-версия Rust (0.1) была выпущена в январе 2012 года[18].

В апреле 2013 года был запущен Servo — экспериментальный проект компании Mozilla по разработке браузерного движка на Rust.[19]

Первая стабильная версия Rust (1.0) вышла в мае 2015 года. Программные интерфейсы и возможности языка подверглись значительной ревизии, после которой по умолчанию оставлены только полностью готовые к применению возможности, реализация которых не будет изменяться в дальнейшем. Все остальные функции переведены в разряд экспериментальных и вынесены из поставки по умолчанию[20].

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

Используется сильная статическая типизация. Поддерживается обобщённое программирование с поддержкой параметрического полиморфизма, обеспечивается автоматический вывод типов для локальных переменных (но не для параметров функций).

Реализована поддержка Шаблон:Iw данных — типов, которые имеют ровно один экземпляр и не занимают места в памяти, примеры:

  • пустой кортеж ();
  • пустой массив (напр. [u8; 0]);
  • структура без полей (напр. struct Foo);
  • структура с единичными типами (struct Foo([u8; 0], ())).

Реализованы Шаблон:Iw данных — типы, экземпляры которых не могут быть созданы; реализованы в виде перечисляемых типов, не имеющих вариантов: enum Void {}.

Все типы данных в языке делятся на две основные группы: простые и типы стандартной библиотеки.

Простые типы (типы постоянной длины, встроенные в сам язык) — числовой, булев, символьный, массив, срез, строковый срез, кортеж, ссылка, указатель на функцию. Часть простых типов является «машинной», то есть реализуются непосредственно в современных процессорах, таковы числовой, булев и символьный. Типы, предоставляемые стандартной библиотекой std (переменной длины): вектор, строка, хеш-таблица и им подобные.

Числовые типы:

  • целое (integer): i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, а также isize и usize, имеющие размер указателя на данной платформе. u8 применяется для «байтовых» значений. Примеры значений: -5i8, 0x400_u16, 0o100i16, 20_922_789_888u64, b'*' (байтовый литерал), b'\x1b', 42 (тип этого значения будет выведен автоматически), 0xfff_fc00usize
  • Число с плавающей запятой (float). f32, f64. Примеры: 3.14f32, 6.0221e23f64, 2.,

Булев (bool): true, false.

Символьный (char): тип, представляющий символ Unicode (внутреннее представление данных как u32). Примеры значений: '₽', '\n', '\x7f', '\u{CA0}',

Указатель на функцию (function pointer): объекты-функции имеют тип, определяемый их сигнатурой, то есть параметрами и возвращаемым значением. Пример: let f: fn(i32) -> i32 = plus_one;

Ссылка (разделяемое заимствование — shared borrow) &T (разделяемая, не изменяемая, не владеющая ресурсом), вместо того, чтобы забирать владение ресурсом, она его заимствует. Имена, которые заимствуют что-то, не освобождают ресурс, когда они выходят из области видимости. Кроме того, имена-владельцы переходят в заимствованное состояние.

Ссылка изменяемая (изменяемое заимствование — mutable borrow) &mut T (не владеющая ресурсом). Позволяет изменять ресурс, который заимствуется.

Структуры (struct):

  • структура си-подобная: struct Color {red: u8, green: u8, blue: u8}
  • структура-кортеж: struct Color (u8, u8, u8);
  • структура — «единичное» значение: struct Electron;

Коллекции:

  • Массив (array) [T; N] — последовательность фиксированного размера N из однотипных (типа T) элементов. Примеры: [1, 2, 3], [true; 10000].
  • Вектор (vec, vector) Vec<T>  — динамический/расширяемый массив. Примеры: vec![0; 10];, Vec::with_capacity(10)
  • Срез (slice, view) &[T]  — это ссылка (или «проекция») на другую структуру данных. Они полезны, когда нужно обеспечить безопасный, эффективный доступ к части массива без копирования. Пример: &a[1..4],
  • Кортеж (tuple) (T1, T2, T3, …). Подобно структуре, содержит произвольное количество разнотипных полей, но поля безымянны, обращение к полям возможно по индексу (t.0, t.1). Кортежи — безымянные типы: кортежи с одинаковым количеством и типами полей являются совместимыми по типу. С помощью ключевого слова type можно задать псевдоним, который, однако, не задаёт нового типа. Пример: ("Age", 22), ("Europe",),
  • Кортеж нулевой длины ((); пустой кортеж) часто называют «единичным значением». Соответственно, тип такого значения  — «единичный тип». Если функция не возвращает значения, то считается, что она возвращает ().
  • Хеш-таблица «ключ — значение» (HashMap) HashMap<T1, T2> — это структура данных, реализующая интерфейс ассоциативного массива, а именно, она позволяет хранить пары (ключ, значение) и выполнять три операции: операцию добавления новой пары, операцию поиска и операцию удаления пары по ключу. Хеш-таблицы в Rust похожи на векторы, и хранят свои значения не по индексу, а по ключу. Пример: HashMap::new();
  • Хеш-таблица — множество (HashSet) HashSet<T> — множество уникальных значений типа T. Добавление и удаление элементов, а также поиск элементов происходит быстрее, чем в других коллекцияхШаблон:Каких?.

Строковые типы:

  • Строка (String) (имеет внутреннее представление данных в виде Vec<u8>) — тип, владеющий содержимым. String представляет собой строку, размещённую в куче. Эта строка расширяема, и она гарантированно является корректной последовательностью байтов с точки зрения UTF-8. String обычно создаётся путём преобразования из строкового среза с использованием метода to_string. Примеры: "строковый срез".to_string(), String::new().
  • «Строковый срез» (string slice, string literal) &str, &'static str. Частный случай среза. Строковые срезы имеют фиксированный размер и не могут быть изменены. Они представляют собой ссылку на последовательность байтов UTF-8. Пример: "строковый срез". &'static str — строка, введённая символами в коде самой программы, — тот же строковый срез, только статически размещённый (сохраняемый в скомпилированной программе).
    • «Сырой строковый срез» (или сырой строковый литерал), в котором не работают управляющие последовательности: r"\d{0,5}.*".
    • «Байтовая строка» &[u8] — строковый литерал с префиксом «b»: b"white".

Перечисление (enum): каждый вариант в перечислении в Rust может быть также связан с другими данными, благодаря чему перечисление называют также tagged union или типом-суммой. Синтаксис для объявления вариантов схож с синтаксисом для объявления структур: могут быть варианты без данных, варианты с именованными данными и варианты с безымянными данными:

  • вариант с «единичным» значением: enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}
  • вариант с конкретным значением: enum Foo {Bar = 123,}.
  • вариант — структура (именованные данные): enum Message {Quit, Move { x: i32, y: i32 }}.
  • вариант — кортежная структура (безымянные данные): enum Message {Quit, Size(i32)}.

Константы:

  • const — постоянные. Живут в течение всего времени работы программы. А именно, у них вообще нет определённого адреса в памяти. Это потому, что они встраиваются (inline) в каждое место, где есть их использование,
  • static — значение с возможностью изменения, имеющее время жизни 'static. Похожи на постоянные, но статические значения не встраиваются в место их использования. Это значит, что каждое значение существует в единственном экземпляре, и у него есть определённый адрес. Также может быть изменяемым, при помощи ключевого слова mut. Изменения возможны только в unsafe блоках.

При выборе следует отдавать предпочтение const, так как зачастую для константы не нужен конкретный адрес в памяти и const позволяет делать оптимизации вроде Свёртки констант.

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

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

Реализована так называемая Move-семантика: по умолчанию Rust «переносит» (move) указатель на объект в куче новому владельцу при присваивании, делая старую переменную недействительной. Этого не происходит, если тип реализует типаж Copy, поскольку данные в стеке копируются.

 let a = "объект с данными в куче".to_string();
// объект передан переменной b
// переменная a становится неинициализированной
let b = a;
// ошибка!
let c = a;
// данные объекта на стеке                                                                                       
let a = 55;
// копия объекта передана переменной b                                                                   
let b = a;
// c = 55                                                                                        
let c = a;

Ещё одна особенность модели памяти — поддержка заимствований (borrow) с возможностью изменения заимствованного объекта (&mut) и без таковой (&): Лексически и семантически очень схожи со ссылками, но имеют специфику: заимствование объекта сходно семантике «Либо много читателей, либо один писатель» — объект можно передать в заимствование либо однократно с возможностью изменения объекта, либо многократно без таковой; заимствования можно перезаимствовать другому заёмщику. В отличие от обычной семантики «Либо много читателей, либо один писатель», применяется не в контексте синхронизации потоков, а универсально. Контроль корректности заимствований происходит во время компиляции и не порождает дополнительного исполнимого кода (принцип абстракций с нулевой стоимостью). Компилятором контролируется также соотношение времён жизни заимствований и самого объекта — заимствования не могут жить дольше (выходить за пределы области видимости) заимствованного объекта. Заимствования работают с любыми данными независимо от их размещения (стек, локальная или обменная куча, другие специальные расположения). Следует различать независимые понятия — изменяемость собственно заимствования (let mut b = &c) и изменяемость заимствованного объекта (let b = &mut c).

Упаковка (Box) — «умный» указатель, владеющий объектом в куче, уничтожает объект и освобождает память при выходе из области видимости.

Ячейка (Cell, RefCell) реализует изменяемость содержимого при неизменяемости самой ячейки.

Указатели со счётчиком ссылок (Rc<T>) и с атомарным счётчиком ссылок (Arc<T>): Умные указатели с подсчётом ссылок, уничтожающие объект и освобождающие память при обнулении счётчика. Arc реализует потокобезопасность для счётчика ссылок (но не для самого объекта). Rc и Arc контролируют неизменяемый объект, поэтому типичное их использование выглядит как Rc<Cell<T>> в однопоточной программе и Arc<Mutex<T>> в многопоточной.

«Сырые» указатели неизменяемые (*const T) и изменяемые (*mut T): Указатели без гарантии безопасности. Настоятельно не рекомендуется их использовать.

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

Примеры:

let x = 80;    // связывание владельца x со значением 80
let mut y = 50;    // изменяемое связывание
let z = &x;    // неизменяемая ссылка на неизменяемое связывание
let w = &mut y;    // неизменяемая ссылка на изменяемое связывание
let r = &mut y;    // ошибка: нельзя создавать вторую ссылку на изменяемое связывание

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

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

В своей докторской диссертации Ральф Юнг (Шаблон:Lang-en) формально доказал потокобезопасность и безопасность управления памятью, использовав логику разделения в созданной им модели RustBelt и инструменте Iris (основанном на Coq)[21].

Синтаксис

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

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

Rust поддерживает макроопределения — средства подстановки с использованием регулярных выражений, выполняющиеся во время этапа подготовки к компиляции, более развитые и безопасные, чем в Си. Макроопределения (макрокоманды) — это определяемые пользователем простые расширения синтаксиса, выполняемые с помощью команды macro_rules! Макрокоманды определяются в том же стиле, что и конструкция сопоставления с образцом. Признак макроса — восклицательный знак в конце имени. Также поддерживаются так называемые «процедурные» макроопределения[23], имеющие возможность исполнять произвольный код во время компиляции.

Связывание имён

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

let x: i32 = 5;

Данная запись обозначает: «x — это связывание типа i32 (32-битное целое) со значением пять».

Сопоставление с образцом (match)

В языке конструкция match представляет собой обобщённую и усовершенствованную версию конструкции switch языка C. Более того, match является самым мощным, универсальным и, можно даже сказать, ключевым элементом управления не только потоком выполнения, но и структурами данных в языке. В выражениях match можно сопоставлять несколько шаблонов, используя синтаксис |, что означает логическое или.

let x = 10;

match x {
    1 | 2 => println!("один или два"),
    3 => println!("три"),
    4..=10 => println!("от четырёх до десяти"), // Отработает эта ветка, ведь 10 принадлежит данному диапазону.
    _ => println!("что угодно, не соответствующее условиям выше"), // "_" соответствует любому значению
}

Деструктуризация

При работе с составными типами данных (структура, перечисление, кортеж, массив) можно разобрать их на части («деструктурировать») внутри шаблона. Деструктуризация структуры:

struct Point {
    x: i32,
    y: i32,
}

let point = Point { x: 0, y: 0 }; 

match point {
    Point { x: 0, y } => println!("x - ноль, y равен {}", y), // так как "x" равен нулю, отработает эта ветка.
    Point { x, y: 0 } => println!("x равен {}, y - ноль", x),
    Point { x, y } => println!("x = {}, y = {}", x, y),
}

Деструктуризация перечисления:

enum Color {
    Rgb(i32, i32, i32),
    Hsv(i32, i32, i32),
}

let color = Color::Hsv(0, 0, 100);

match color {
    Color::Rgb(0, 0, 0) | Color::Hsv(0, 0, 0) => println!("чёрный"),
    Color::Rgb(255, 255, 255) | Color::Hsv(0, 0, 100) => println!("белый"), // отработает эта ветка.
    Color::Rgb(red, green, blue) => {
        println!("красный: {}, зелёный: {}, синий: {}", red, green, blue)
    } // отработает при любых значениях Rgb, которые не соответствуют условиям выше.
    Color::Hsv(hue, saturation, brightness) => println!(
        "тон: {}, насыщенность: {}, яркость: {}",
        hue, saturation, brightness
    ), // то же самое, только с Hsv.
}

Деструктуризация кортежа:

let (a, b) = (1, 2);

println!("{}", a); // 1
println!("{}", b); // 2

Условные выражения (if let)

Синтаксис if let позволяет скомбинировать if и let в менее многословную конструкцию, и затем обработать значения соответствующе только одному шаблону, одновременно игнорируя все остальные. Данный синтаксис уместно использовать, когда нужно сопоставить только один шаблон.

let x = Some(10);

if let Some(value) = x {
    // здесь мы деструктурируем x, переменная value хранит значение 10.
    // выполнится эта ветка, так как "x" хранит внутри значение.
    println!("значение = {}", value);
} else {
    // оператор "else" здесь выступает заменой "_" в выражениях match.
    println!("x - пуст");
}

unsafe

В блоках и функциях, помеченных unsafe (Шаблон:Tr-en), компилятор разрешает делать лишь пять дополнительных вещей:

  • читать и обновлять изменяемые статические (static mut) переменные;
  • разыменовывать сырые указатели;
  • вызывать небезопасные (unsafe) функции;
  • реализовывать небезопасные типажи;
  • Получать доступ к полям union.

К unsafe приходится прибегать при создании низкоуровневых абстракций, в частности — при разработке стандартной библиотеки Rust; обычный код рекомендуется писать без unsafe.

Объектная система

В Rust объектная система основана на типажах (Шаблон:Lang-en2) и структурах (Шаблон:Lang-en2). Типажи определяют сигнатуры методов, которые должны быть реализованы для каждого типа (чаще всего — структуры), реализующего типаж. Типаж может содержать и реализации методов, принимаемые по умолчанию. Реализация типажей для данной структуры, а также реализация собственных методов структуры обозначается ключевым словом impl. Язык содержит несколько десятков встроенных типажей, большая часть которых используется для перегрузки операторов, а некоторые имеют специальное значение.

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

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

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

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

Определение и вызов асинхронных операций поддерживаются на уровне синтаксиса языка: ключевое слово async определяет асинхронную функцию или блок; обычный вызов такой функции возвращает объект с типажом Future — дескриптор ленивой асинхронной операции[25]. Вызов .await позволяет одной асинхронной операции ждать, пока не завершится другая асинхронная операция. При этом реализация среды исполнения асинхронных операций не входит ни в ядро языка, ни в стандартную библиотеку, а предоставляется сторонними библиотеками[26].

Другие особенности

Система модулей: единица компиляции («крейт») может состоять из нескольких модулей. Иерархия модулей, как правило, совпадает с иерархией каталогов и файлов проекта. Модуль (как правило) является отдельным файлом, а также является пространством имён и одним из средств управления видимостью идентификаторов: в пределах модуля (и в подмодулях) «видны» все идентификаторы, в вышестоящих модулях видны только публичные (pub) функции, типы, типажи, константы, подмодули, поля структур.

Автоматизированное тестирование: язык даёт возможность реализовать автоматизированные модульные тесты (юнит-тесты) прямо в тестируемом модуле либо подмодуле. Тестовые методы при компиляции игнорируются и вызываются только при тестировании. Интеграционные тесты реализуются как отдельные крейты в каталоге tests.

Автоматизированное документирование: средство rustdoc позволяет генерировать HTML-документацию прямо из исходного кода. Документация в коде маркируется тройным слешем (/// Пример документации) либо двойным с восклицательным знаком, для документации модулей — (//! Пример документации модуля). Поддерживается язык разметки Markdown. В документацию может быть встроен код, который является запускаемым (документационные тесты). Это позволяет, в том числе, проверять актуальность документации при внесении изменений в проект.

Система управления пакетами: менеджер пакетов cargo (являющийся также основным инструментом создания, компиляции и тестирования проектов) с помощью файла манифеста Cargo.Шаблон:Нп5 разрешает зависимости проекта (импортируемые крейты), загружая их из репозитория crates.io.

Требования к идентификаторам: компилятор контролирует выполнение соглашений об именовании переменных, типов, функций и так далее (snake_case, UpperCamelCase, SCREAMING_SNAKE_CASE), а также неиспользуемые идентификаторы; неиспользуемые идентификаторы рекомендуется начинать со знака подчёркивания; есть определённые рекомендации по именованию конструкторов, методов преобразования типов и др.[27]

Примеры

Hello, world!:

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

99 бутылок пива:

fn declension_of_noun(count: u8) -> &'static str {
    let remainder = count % 10;

    // исключения из правил
    if count == 11 || count >= 12 && count <= 14 {
        return "бутылок";
    }

    match remainder {
        1 => return "бутылка",
        2..=4 => return "бутылки",
        _ => return "бутылок",
    }
}

fn main() {
    let mut word = declension_of_noun(99);

    for i in (2..=99).rev() {
        println!("{} {} пива на стене", i, word);
        println!("{} {} пива!", i, word);
        println!("Возьми одну, пусти по кругу");

        word = declension_of_noun(i - 1);

        println!("{} {} пива на стене!\n", i - 1, word);
    }

    println!("1 бутылка пива на стене");
    println!("1 бутылка пива!");
    println!("Возьми одну, пусти по кругу");
    println!("Нет больше бутылок пива на стене!\n");
    println!("Нет бутылок пива на стене!");
    println!("Нет бутылок пива!");
    println!("Пойди в магазин и купи ещё");
    println!("99 бутылок пива на стене!");
}

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

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

Язык позволяет объявлять функции и блоки кода как «небезопасные» (unsafe). В области такого небезопасного кода не применяются некоторые ограничения, таким образом можно выполнять операции на более низком уровне, но разработчик должен полностью понимать, что он делает.

Примечания

Шаблон:Примечания

Литература

Ссылки

Шаблон:Mozilla Software

  1. 1,0 1,1 Шаблон:Публикация
  2. Шаблон:Cite web
  3. Шаблон:Книга
  4. Шаблон:Cite web
  5. Шаблон:Cite web
  6. Шаблон:Cite web
  7. Шаблон:Cite web
  8. Шаблон:Cite web
  9. Шаблон:Cite web
  10. Шаблон:Cite web
  11. Шаблон:Cite web
  12. Шаблон:Cite web
  13. Шаблон:Cite web
  14. Шаблон:Cite web
  15. Шаблон:Cite web
  16. Шаблон:Cite web
  17. Шаблон:Cite web
  18. Шаблон:Cite web
  19. Шаблон:Cite web
  20. Шаблон:Cite web
  21. Шаблон:Публикация
  22. В частности, поддерживается неявное приведение ссылки к указателю; изменяемой ссылки (указателя) к неизменяемой ссылке (указателю); объекта определённого типа к объекту с типажом, реализованным этим типом. Отсутствует неявное приведение чисел или строк к булевому значению.
  23. Шаблон:Cite web
  24. Шаблон:Cite web
  25. Шаблон:Cite web
  26. Шаблон:Cite web
  27. Шаблон:Cite web