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

Rust на примерах. Часть 1

Этот цикл статей является вольным переводом книги «Rust by Example», которую пишет Хорхе Апарисио на Github.

На момент написания этого топика автор книги создал 49 глав, в первой части будет перевод первых пяти. Убедитесь, что Rust установлен и под рукой имеется документация.

Содержание

  1. При написании программ использовался компилятор версии Nightly (0.10), не забудьте про это.
  2. Запустить код можно в Rust Playpen (кнопка «evaluate»): http://play.rust-lang.org

1. Привет, мир!

// Комментарии игнорируются компилятором // Это основная функция fn main() < // Вывести текст в консоль println!("Hello World!"); >

println! это макрос (мы рассмотрим их позже), который печатает текст в консоль.

Программа может быть сгенерирована с помощью компилятора Rust rustc:

2. Форматированный вывод

Макрос println! не только выводит в консоль, а также способен форматировать текст и сериализованные значения. Корректность проверяется во время компиляции.

fn main() < // `print!`, как `println!`, но он не добавляет новую строку в конце print!("January has "); // `<>` это заполнители для аргументов, которые будут строками println!("<> days", 31i); // `i` суффикс указывает компилятору, что этот литерал имеет тип: целое // число со знаком, смотрите следующую главу для более подробной информации // Позиционные аргументы могут быть повторно использованы по шаблону println!(", this is . , this is ", "Alice", "Bob"); // Аргументы можно называть println!("  ", predicate="over the lazy dog", subject="the quick brown fox", verb="jumps"); // Специальное форматирование может быть указано в заполнителе после `:`, `t` это бинарное представление println!("<> of people know binary, the other half don't", 1i, 2i); // Ошибка! Не хватает аргумента для вывода println!("My name is , ", "Bond"); // ИСПРАВЬТЕ ^ добавьте отсутствующий аргумент: "James" > 

Дополнительная информация о форматировании здесь: std​::fmt​

Читайте также:  Колледж программирования в академгородке

3. Литералы и операторы

Целые числа 1, с плавающей точкой 1.2, символы ‘a’, строки «abc» , логические true и значения пустого типа () могут быть выражены с помощью литералов.

Также целые числа можно выразить через шестнадцатеричное, восьмеричное или двоичное обозначение, используя один из префиксов: 0x, 0o или 0b.

В числовые литералы можно вставлять подчёркивания для читабельности, например, 1_000 такой же, как и 1000, а 0.000_001 такой же, как и 0.000001.

Мы должны сказать компилятору, какой из литералов мы используем. Сейчас мы будем использовать суффикс u , указывающий, что литерал является целым числом без знака, суффикс i чтобы указать, что это знаковое целое число. Мы рассмотрим систему типов в 5 главе, а также подробную информацию о аннотировании литералов.

Доступные операторы и их приоритет похож на C-подобных языках.

fn main() < // Целочисленное сложение println!("1 + 2 = <>", 1u + 2); // Вычитание println!("1 - 2 = <>", 1i - 2); // Попробуйте изменить `1i` на `1u` и понять, почему тип важен // Булева логика println!("true AND false is <>", true && false); println!("true OR false is <>", true || false); println!("NOT true is <>", !true); // Битовые операции println!("0011 AND 0101 is ", 0b0011u & 0b0101); println!("0011 OR 0101 is ", 0b0011u | 0b0101); println!("0011 XOR 0101 is ", 0b0011u ^ 0b0101); println!("1 ", 1u > 2 is 0x", 0x80u >> 2); // Используйте подчеркивания, чтобы улучшить читаемость println!("One million is written as <>", 1_000_000u); > 

4. Переменные

Значения (как и литералы) могут быть связаны с переменными, используя обозначение let.

fn main() < let an_integer = 1u; let a_boolean = true; let unit = (); // скопировать значение `an_integer` в `copied_integer` let copied_integer = an_integer; println!("An integer: <>", copied_integer); println!("A boolean: <>", a_boolean); println!("Meet the unit value: <>", unit); // Компилятор предупреждает о неиспользуемых переменных; эти предупреждения можно // отключить используя подчёркивание перед именем переменной let _unused_variable = 3u; let noisy_unused_variable = 2u; // ИСПРАВЬТЕ ^ Добавьте подчёркивание > 
4.1 Изменяемость

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

fn main() < let _immutable_variable = 1i; let mut mutable_variable = 1i; println!("Before mutation: <>", mutable_variable); // Ок mutable_variable += 1; println!("After mutation: <>", mutable_variable); // Ошибка! _immutable_variable += 1; > 

Компилятор будет выводить сообщения об ошибке изменчивости.

4.2 Области и видимость

Переменные имеют локальную область, и имеют видимость в блоке (блок представляет собой набор операторов, заключённых в фигурные скобки <>). Кроме того, допускается скрытие переменной.

fn main() < // Эта переменная живет в области функции main let long_lived_variable = 1i; // Это блок, он имеет меньший объем нежели основная функция < // Эта переменная существует только в этом блоке let short_lived_variable = 2i; println!("inner short: <>", short_lived_variable); // Эта переменная не видна внешней функции let long_lived_variable = 5_f32; println!("inner long: <>", long_lived_variable); > // Конец блока // Ошибка! `short_lived_variable` не существует в этой области println!("outer short: <>", short_lived_variable); // ИСПРАВЬТЕ ^ Закомментируйте строку println!("outer long: <>", long_lived_variable); > 
4.3 Предварительное объявление

Можно сперва объявлять переменные, а инициализировать их позже. Но эта форма редко используется, так как это может привести к использованию неинициализированных переменных.

fn main() < // Объявляем переменную let a_variable; < let x = 2i; // Инициализируем переменную a_variable = x * x; >println!("a variable: <>", a_variable); let another_variable; // Ошибка! Использование неинициализированной переменной println!("another variable: <>", another_variable); // ИСПРАВЬТЕ ^ Закомментируйте строку another_variable = 1i; println!("another variable: <>", another_variable); > 

Компилятор запрещает использование неинициализированных переменных, так как это привело бы к непредсказуемым последствиям.

5. Типы

Rust обеспечивает безопасность с помощью статической проверки типов. Тип переменной может быть явно указан при её объявлении. Тем не менее, в большинстве случаев, компилятор сможет определить тип переменной из контекста, если это очевидно.

  • целые числа: i8 , i16 , i32 , i64 и int (размер зависит от платформы)
  • целые числа без знака: u8 , u16 , u32 , u64 и uint (размер зависит от платформы)
  • с плавающей точкой: f32 , f64
  • char значения Unicode: ‘a’, ‘α’ и ‘∞’ (4 байта каждый)
  • bool true или false
  • кортежи ()
5.1 Приведение типов

Rust не предоставляет неявного преобразования типов (coercion) между примитивами, но, явное приведение типов (casting) может быть достигнуто с помощью ключевого слова as.

fn main() < let decimal = 65.4321_f32; // Ошибка! Нет неявного преобразования let integer: u8 = decimal; // ИСПРАВЬТЕ ^ Закомментируйте строку // Явное преобразование let integer = decimal as u8; let character = integer as char; println!("Casting: <>-> <> -> <>", decimal, integer, character); > 
5.2 Литералы

В числовых литералах тип может быть аннотирован, добавив тип в качестве суффикса, за исключением uint , использующей суффикс u и int , который использует суффикс i .

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

fn main() < // Литералы с суффиксами, их вид известен при инициализации let x = 1u8; let y = 2u; let z = 3f32; // Литералы без суффикса, их вид зависит от того, как они используются let i = 1; let f = 1.0; // `size_of_val` возвращает размер переменной в байтах println!("size of `x` in bytes: <>", std::mem::size_of_val(&x)); println!("size of `y` in bytes: <>", std::mem::size_of_val(&y)); println!("size of `z` in bytes: <>", std::mem::size_of_val(&z)); println!("size of `i` in bytes: <>", std::mem::size_of_val(&i)); println!("size of `f` in bytes: <>", std::mem::size_of_val(&f)); // Ограничения (слагаемые должны иметь тот же тип) для `i` и `f` let _constraint_i = x + i; let _constraint_f = z + f; // Закомментируйте эти две строки > 
  • fun(&foo) используется, чтобы передать аргумент в функцию по ссылке, а не по значению fun(foo) .
  • std::mem::size_of_val является функцией, но вызывается с указанием полного пути. Код можно разделить на логические единицы, называемые модулями. Здесь функция size_of_val определена в модуле mem , а модуль mem определен в крэйте std .
5.3 Логический вывод

Логический вывод типов довольно умён. Тип добавляемой переменной используется как определитель типа для второй переменной. Вот продвинутый пример:

fn main() < // Использование локального вывода, компилятор знает, что `elem` имеет тип `u8` let elem = 5u8; // Создадим пустой вектор (расширяемый массив) let mut vec = Vec::new(); // В этот момент компилятор не знает точный тип `vec`, он // просто знает, что это вектор `Vec` // Вставим `elem` в вектор vec.push(elem); // Ага! Теперь компилятор знает, что `vec` это вектор `u8` (`Vec`) // Попробуйте закомментировать строку `vec.push(elem)` println!("<>", vec); > 

Отсутствует необходимость в аннотации типа переменной, компилятор счастлив как и программист!

5.4 Псевдонимы (алиасы)

Оператор type может быть использован, чтобы задать новое имя существующему типу. Тип должен быть в стиле CamelCase, либо компилятор выдаст предупреждение. Исключением из этого правила являются примитивные типы: uint , f32 и другие.

// `NanoSecond` это новое имя для `u64` type NanoSecond = u64; type Inch = u64; // Используйте этот атрибут, чтобы не выводить предупреждение #[allow(non_camel_case_types)] type uint64_t = u64; // Попробуйте удалить атрибут fn main() < // `NanoSecond` = `Inch` = `uint64_t` = `u64` let nanoseconds: NanoSecond = 5 as uint64_t; let inches: Inch = 2 as uint64_t; // Обратите внимание, что псевдонимы новых типов не предоставляют // дополнительную безопасность, из-за того, что они не нового типа println!("<>nanoseconds + <> inches = <> unit?", nanoseconds, inches, nanoseconds + inches); > 

Основное применение псевдонимов это снижение количества кода, например, тип IoResult является псевдонимом типа Result .

Заключение

Присоединяйтесь к google-группе: Rust по-русски для получения дополнительной информации по этому языку.
Можно помочь с переводом на Github: github.com/eg0r/rust-by-example

Все замечания, ошибки или неточности отправляйте мне в почту.

Источник

Rust by Example

Rust is a modern systems programming language focusing on safety, speed, and concurrency. It accomplishes these goals by being memory safe without using garbage collection.

Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries. To get even more out of these examples, don’t forget to install Rust locally and check out the official docs. Additionally for the curious, you can also check out the source code for this site.

  • Hello World — Start with a traditional Hello World program.
  • Primitives — Learn about signed integers, unsigned integers and other primitives.
  • Custom Types — struct and enum .
  • Variable Bindings — mutable bindings, scope, shadowing.
  • Types — Learn about changing and defining types.
  • Conversion
  • Expressions
  • Flow of Control — if / else , for , and others.
  • Functions — Learn about Methods, Closures and Higher Order Functions.
  • Modules — Organize code using modules
  • Crates — A crate is a compilation unit in Rust. Learn to create a library.
  • Cargo — Go through some basic features of the official Rust package management tool.
  • Attributes — An attribute is metadata applied to some module, crate or item.
  • Generics — Learn about writing a function or data type which can work for multiple types of arguments.
  • Scoping rules — Scopes play an important part in ownership, borrowing, and lifetimes.
  • Traits — A trait is a collection of methods defined for an unknown type: Self
  • Macros
  • Error handling — Learn Rust way of handling failures.
  • Std library types — Learn about some custom types provided by std library.
  • Std misc — More custom types for file handling, threads.
  • Testing — All sorts of testing in Rust.
  • Unsafe Operations
  • Compatibility
  • Meta — Documentation, Benchmarking.

Источник

Rust на примерах

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

Rust на примерах (Rust by Example, RBE) — это набор исполняемых примеров, которые иллюстрируют различные концепции языка Rust, а так же возможности его стандартной библиотеки. Для того, чтобы почерпнуть ещё больше из этих примеров, не забудьте установить Rust на своём компьютере и ознакомиться с официальной документацией. Самые любознательные могут заглянуть в исходный код этого сайта.

  • Hello World — начнём с традиционной программы Hello World.
  • Примитивы — узнаем о целых числах со знаком, целых числах без знака и других примитивах.
  • Пользовательские типы — struct и enum .
  • Связывание переменных — изменяемые связывания, область видимости, затенение.
  • Типы — изменение и определение типов.
  • Преобразования.
  • Выражения.
  • Управление потоком — if / else , for и другие.
  • Функции — узнаем о методах, замыканиях и функциях высокого порядка.
  • Модули — организуем код с помощью модулей.
  • Пакет — единица компиляции в Rust. Научимся создавать библиотеку.
  • Cargo — познакомимся с основными функциями официального пакетного менеджера Rust.
  • Атрибуты — метаданные, применяемые к какому-либо модулю, пакету или элементу.
  • Обобщения — узнаем о написании функции или типа данных, которые могут работать для нескольких типов аргументов.
  • Правила областей видимости — области видимости играют важную роль во владении, заимствовании и продолжительности жизни.
  • Трейты — это набор методов, определённых для неизвестного типа: Self .
  • Макросы.
  • Обработка ошибок — узнаем, как это делать в Rust.
  • Типы стандартной библиотеки — изучим некоторые пользовательские типы, предоставленные стандартной библиотекой.
  • Разное в стандартной библиотеке — больше пользовательских типов для обработки файлов, потоков.
  • Тестирование — все виды тестов в Rust.
  • Unsafe.
  • Совместимость.
  • Meta — документация, бенчмаркинг.

Источник

Оцените статью