--- filename: learnrust-ru.rs contributors: - ["P1start", "http://p1start.github.io/"] translators: - ["Anatolii Kosorukov", "https://github.com/java1cprog"] - ["Vasily Starostin", "https://github.com/Basil22"] --- Язык Rust разработан в Mozilla Research. Он сочетает низкоуровневую производительность с удобством языка высокого уровня и одновременно гарантирует безопасность памяти. Он достигает этих целей без сборщика мусора или сложной среды выполнения, что позволяет использовать библиотеки Rust как прямую замену C-библиотек. И наоборот, Rust умеет использовать готовые С-библиотеки как есть, без накладных расходов. Первый выпуск Rust, 0.1, произошел в январе 2012 года. В течение 3 лет развитие продвигалось настолько быстро, что язык серьезно менялся без сохранения совместимости. Это дало возможность обкатать и отполировать синтаксис и возможности языка. 15 мая 2015 года был выпущен Rust 1.0 с полной гарантией обратной совместимости. Сборка поставляется в трех вариантах: стабильная версия, бета-версия, ночная версия. Все нововведения языка сперва обкатываются на ночной и бета-версиях, и только потом попадают в стабильную. Выход очередной версии происходит раз в 6 недель. В 2018 году вышло второе большое обновление языка, добавившее ему новых возможностей. Хотя Rust является языком относительно низкого уровня, он имеет все возможности высокоуровневых языков: процедурное, объектное, функциональное, шаблонное и другие виды программирования. На данный момент Rust является одним из самых мощных (а может быть и самым) по возможностям среди статически типизированных языков. Это делает Rust не только быстрым, но и простым и эффективным для разработки сложного кода. ```rust // Это однострочный комментарий // /// Так выглядит комментарий для документации /// # Examples /// /// ``` /// let seven = 7 /// ``` /////////////// // 1. Основы // /////////////// // Функции // `i32` это целочисленный знаковый тип 32-bit #[allow(dead_code)] fn add2(x: i32, y: i32) -> i32 { // метод возвращает сумму x и y x + y } // Главная функция программы #[allow(unused_variables)] #[allow(unused_assignments)] #[allow(dead_code)] fn main() { // Числа // // неизменяемая переменная let x: i32 = 1; // Суффиксы целое/дробное let y: i32 = 13i32; let f: f64 = 1.3f64; // Автоматическое выведение типа данных // В большинстве случаев компилятор Rust может вычислить // тип переменной, поэтому вам не нужно явно указывать тип. let implicit_x = 1; let implicit_f = 1.3; // Арифметика let sum = x + y + 13; // Изменяемая переменная let mut mutable = 1; mutable = 4; mutable += 2; // Строки // // Строковые литералы let x: &str = "hello world!"; // Печать на консоль println!("{} {}", f, x); // 1.3 hello world // `String` – изменяемая строка let s: String = "hello world".to_string(); // Строковый срез - неизменяемое представление части строки // Представляет собой пару из указателя на начало фрагмента и его длины let s_slice: &str = &s; println!("{} {}", s, s_slice); // hello world hello world // Vectors/arrays // // фиксированный массив let four_ints: [i32; 4] = [1, 2, 3, 4]; // динамический массив let mut vector: Vec = vec![1, 2, 3, 4]; vector.push(5); // Срез - неизменяемое представление значений вектора let slice: &[i32] = &vector; // Используйте шаблон `{:?}`для печати отладочной информации структур с данными println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] // Кортежи // // Кортеж - это фиксированный набор. // В нём могут находиться значения разных типов данных. let x: (i32, &str, f64) = (1, "hello", 3.4); // Инициализация группы переменных `let` let (a, b, c) = x; println!("{} {} {}", a, b, c); // 1 hello 3.4 // Доступ по индексу println!("{}", x.1); // hello ////////////// // 2. Типы // ////////////// // Структура struct Point { x: i32, y: i32, } let origin: Point = Point { x: 0, y: 0 }; // Структуры могут быть с безымянными полями ‘tuple struct’ struct Point2(i32, i32); let origin2 = Point2(0, 0); // Перечисление enum Direction { Left, Right, Up, Down, } let up = Direction::Up; // Перечисление с полями // В отличие от C и C++ компилятор автоматически следит за тем, // какой именно тип хранится в перечислении. enum OptionalI32 { AnI32(i32), Nothing, } let two: OptionalI32 = OptionalI32::AnI32(2); let nothing = OptionalI32::Nothing; // Обобщенные типы данных // struct Foo { bar: T } // Частоиспользуемое перечисление стандартной библиотеки `Option` enum Optional { SomeVal(T), NoVal, } // Методы // impl Foo { fn get_bar(self) -> T { self.bar } } let a_foo = Foo { bar: 1 }; println!("{}", a_foo.get_bar()); // 1 // Типаж trait Frobnicate { fn frobnicate(self) -> Option; } impl Frobnicate for Foo { fn frobnicate(self) -> Option { Some(self.bar) } } let another_foo = Foo { bar: 1 }; println!("{:?}", another_foo.frobnicate()); // Some(1) ///////////////////////////////// // 3. Сопоставление по шаблону // ///////////////////////////////// let foo = OptionalI32::AnI32(1); match foo { OptionalI32::AnI32(n) => println!("it’s an i32: {}", n), OptionalI32::Nothing => println!("it’s nothing!"), } // Более сложный пример struct FooBar { x: i32, y: OptionalI32 } let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) }; match bar { FooBar { x: 0, y: OptionalI32::AnI32(0) } => println!("The numbers are zero!"), FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m => println!("The numbers are the same"), FooBar { x: n, y: OptionalI32::AnI32(m) } => println!("Different numbers: {} {}", n, m), FooBar { x: _, y: OptionalI32::Nothing } => println!("The second number is Nothing!"), } ////////////////////////////////////////////// // 4. Управление ходом выполнения программы // ////////////////////////////////////////////// // `for` loops/iteration let array = [1, 2, 3]; for i in array { println!("{}", i); } // Диапазоны for i in 0u32..10 { print!("{} ", i); } println!(""); // prints `0 1 2 3 4 5 6 7 8 9 ` // `if` if 1 == 1 { println!("Maths is working!"); } else { println!("Oh no..."); } // `if` as expression let value = if true { "good" } else { "bad" }; // `while` loop while 1 == 1 { println!("The universe is operating normally."); break; } // Infinite loop loop { println!("Hello!"); break; } ////////////////////////////////// // 5. Защита памяти и указатели // ////////////////////////////////// // Владеющий указатель – такой указатель может быть только один // Это значит, что при выходе из блока переменная автоматически становится недействительной. let mut mine: Box = Box::new(3); *mine = 5; // dereference // Здесь, `now_its_mine` получает во владение `mine`. Т.е. `mine` была перемещена. let mut now_its_mine = mine; *now_its_mine += 2; println!("{}", now_its_mine); // 7 // println!("{}", mine); // Ссылки - это неизменяемые указатели // Если ссылка получает значения, то говорят, что она заимствует это значение. // Такое значение не может быть изменено или перемещено. let mut var = 4; var = 3; let ref_var: &i32 = &var; println!("{}", var); println!("{}", *ref_var); // var = 5; // не скомпилируется // *ref_var = 6; // и это // Изменяемые ссылки // let mut var2 = 4; let ref_var2: &mut i32 = &mut var2; *ref_var2 += 2; // '*' используется для изменения значения println!("{}", *ref_var2); // 6 , // var2 would not compile. // ref_var2 имеет тип &mut i32, т.е. он содержит ссылку на i32, а не значение. // var2 = 2; // не скомпилируется, т.к. эта переменная уже была заимствована ранее } ``` ## Более подробная информация о языке Уже есть хорошие книги для изучающих Rust. Основным источником остаётся [The Rust Programming Language](http://doc.rust-lang.org/book/index.html) Для компиляции программ при изучении языка весьма удобно использовать [Rust Playground](https://play.rust-lang.org). Множество ресурсов на разных языках можно найти в [этом проекте](https://github.com/ctjhoa/rust-learning).