Всем привет. Недавно я познакомился с новым языком программирования Rust. Я заметил, что он отличался от других, с которыми я сталкивался раньше.
Поэтому я решил копнуть глубже.
Хочу поделиться результатами и впечатлениями:
- Начну с главной, на мой взгляд, особенности Rust.
- Опишу интересные детали синтаксиса
- Я объясню, почему Rust, скорее всего, не захватит мир.
Убийственная особенность Rust пытается занять промежуточную позицию между низкоуровневыми языками вроде C/C++ и высокоуровневыми Java/C#/Python/Ruby. Чем ближе язык к аппаратному обеспечению, тем больше у него контроля, тем проще это значит предсказать, как будет выполняться код. Но даже имея полный доступ к памяти, гораздо проще выстрелить себе в ногу.
В отличие от C/C++ появился Python/Java и все остальные.
Не нужно думать об очистке памяти.
Худшая проблема — это NPE; утечки – не такое уж частое явление.
Но чтобы это работало, как минимум, необходим сборщик мусора, который, в свою очередь, начинает жить своей жизнью параллельно с пользовательским кодом, снижая его предсказуемость.
Виртуальная машина также обеспечивает независимость от платформы, но насколько это необходимо — вопрос спорный; Я не буду поднимать его сейчас.
Rust — язык низкого уровня; на выходе компилятор выдает бинарник, для работы не требующий дополнительных хитростей.
Вся логика удаления ненужных объектов интегрируется в код во время компиляции, т.е.
сборка мусора во время выполнения также отсутствует. Rust также не имеет нулевых ссылок и является типобезопасным, что делает его даже более надежным, чем Java. Управление памятью основано на идее владения и заимствования ссылки на объект. Если каждому объекту принадлежит только одна переменная, то как только в конце блока истечет время его жизни, все, на что он указывал, может быть рекурсивно очищено.
Вы также можете брать ссылки для чтения или записи.
Здесь работает принцип одного писателя и многих читателей.
Эту концепцию можно продемонстрировать в следующем фрагменте кода.
Из метода основной() называется тест() , в котором создается рекурсивная структура данных МояСтрукт , который реализует интерфейс деструктора.
Уронить позволяет указать логику, которая будет выполняться перед уничтожением объекта.
Что-то похожее на финализатор в Java, только в отличие от Java момент вызова метода уронить() вполне определенный.
Результат будет следующим:fn main() { test(); println!("End of main") } fn test() { let a = MyStruct { v: 1, s: Box::new( Some(MyStruct { v: 2, s: Box::new(None), }) ), }; println!("End of test") } struct MyStruct { v: i32, s: Box<Option<MyStruct>>, } impl Drop for MyStruct { fn drop(&mut self) { println!("Cleaning {}", self.v) } }
End of test
Cleaning 1
Cleaning 2
End of main
Те.
перед уходом тест() память была рекурсивно очищена.
Компилятор позаботился об этом, вставив необходимый код. Что случилось Коробка И Вариант Опишу чуть позже.
Таким образом, Rust берет безопасность от языков высокого уровня и предсказуемость от языков программирования низкого уровня.
Что еще интересно Далее я перечислю особенности языка в порядке убывания важности, на мой взгляд.
ООП
Здесь Rust вообще впереди планеты всей.Если в большинстве языков пришли к выводу, что необходимо отказаться от множественного наследования, то в Rust наследование отсутствует вообще.
Те.
класс может реализовывать интерфейсы только в любом количестве, но не может наследовать от других классов.
В терминах Java это означало бы сделать все классы окончательными.
В общем, синтаксическое разнообразие для поддержки ООП не так уж и велико.
Возможно, это к лучшему.
Для объединения данных существуют структуры, которые могут содержать реализацию.
Интерфейсы называются типажами и также могут содержать реализацию по умолчанию.
До абстрактных классов они не доходят, т. к.
не могут содержать поля, на это ограничение многие жалуются.
Синтаксис выглядит так, думаю комментарии здесь не нужны: fn main() {
MyPrinter { value: 10 }.
print();
}
trait Printer {
fn print(&self);
}
impl Printer {
fn print(&self) {
println!("hello!")
}
}
struct MyPrinter {
value: i32
}
impl Printer for MyPrinter {
fn print(&self) {
println!("{}", self.value)
}
}
Из особенностей, которые я заметил, стоит отметить следующие:
- Классы не имеют конструкторов.
Есть только инициализаторы, которые устанавливают значения полям через фигурные скобки.
Если необходим конструктор, это делается с помощью статических методов.
- Метод экземпляра отличается от статического метода наличием ссылки.
&себя в качестве первого аргумента.
- Классы, интерфейсы и методы также могут быть универсальными.
Но в отличие от Java эта информация не теряется во время компиляции.
Еще немного безопасности
Как я уже говорил, Rust уделяет большое внимание надежности кода и старается предотвратить большинство ошибок во время компиляции.Для этого была удалена возможность делать ссылки пустыми.
Это чем-то напомнило мне обнуляемые типы из Котлина.
Используется для создания пустых ссылок Вариант .
Как и в Котлине, когда вы пытаетесь получить доступ к такой переменной, компилятор сильно вас бьет, заставляя вставлять проверки.
Попытка извлечь значение без проверки может привести к ошибке.
Но это уж точно нельзя сделать случайно, как, например, в Java. Мне также понравилось то, что все переменные и поля классов по умолчанию неизменяемы.
Привет, Котлин, еще раз.
Если значение может измениться, это должно быть явно указано с помощью ключевого слова мут .
Я думаю, что стремление к неизменности значительно улучшает читаемость и предсказуемость кода.
Хотя Вариант Почему-то он изменчивый, я этого не понял, вот код из документации: let mut x = Some(2);
let y = x.take();
assert_eq!(x, None);
assert_eq!(y, Some(2));
Трансферы
В Rust они называются перечисление .Помимо ограниченного числа значений, они также могут содержать произвольные данные и методы.
Таким образом, они представляют собой что-то среднее между перечислениями и классами в Java. Стандартный вариант перечисления в моем первом примере он принадлежит только этому типу: pub enum Option<T> {
None,
Some(T),
}
Для обработки таких значений существует специальная конструкция: fn main() {
let a = Some(1);
match a {
None => println!("empty"),
Some(v) => println!("{}", v)
}
}
И
Моя цель — не написать учебник по Rust, а просто подчеркнуть его возможности.В этом разделе я опишу, что еще полезно, но, на мой взгляд, не столь уникально:
- Любители функционального программирования не будут разочарованы, для них есть лямбды.
У итератора есть методы для обработки коллекции, например.
фильтр И для каждого .
Что-то похожее на потоки из Java.
- Дизайн соответствовать также можно использовать для более сложных вещей, чем обычные перечисление , например, для обработки шаблонов
- Существует большое количество встроенных классов, например, коллекций: Век, LinkedList, HashMap и т. д.
- Вы можете создавать макросы
- Можно добавлять методы в существующие классы.
- Поддерживается автоматический вывод типа
- Язык поставляется со стандартной средой тестирования.
- Встроенная утилита используется для построения зависимостей и управления ими.
груз
Проблема убийцы
Главный недостаток вытекает из основной особенности.За все нужно платить.
В Rust очень неудобно работать с изменяемыми графовыми структурами данных, потому что.
На любой объект не должно быть более одной ссылки.
Чтобы обойти это ограничение, существует несколько встроенных классов:
- Коробка — неизменяемое значение в куче, аналог оберток для примитивов в Java
- Клетка — изменяемое значение
- РефСелл — изменяемое значение, доступно по ссылке
- Rc — счетчик ссылок, для нескольких обращений к одному объекту
Во время моей первой попытки работать с Rust я опрометчиво решил написать односвязный список с базовыми методами.
В конечном итоге ссылка на ноду оказалась следующей Вариант > > :
- Вариант — для обработки пустой ссылки
- Rc - для нескольких ссылок, поскольку на последний объект ссылается предыдущий узел и сам лист
- РефСелл - для изменяемой ссылки
- СписокNode — сам следующий элемент
Код простого добавления элемента в конец списка очень громоздкий, и в нем есть неочевидные вещи, такие как клонирование и заимствование: struct ListNode {
val: i32,
next: Node,
}
pub struct LinkedList {
root: Node,
last: Node,
}
type Node = Option<Rc<RefCell<ListNode>>>;
impl LinkedList {
pub fn add(mut self, val: i32) -> LinkedList {
let n = Rc::new(RefCell::new(ListNode { val: val, next: None }));
if (self.root.is_none()){
self.root = Some(n.clone());
}
self.last.map(|v| { v.borrow_mut().
next = Some(n.clone()) }); self.last = Some(n); self } .
В Котлине то же самое выглядит гораздо проще: public fun add(value: Int) {
val newNode = ListNode(null, value);
root = root ?: newNode;
last?.
next = newNode
last = newNode;
}
Как я позже узнал, такие структуры не типичны для Rust, а мой код совершенно неидиоматичен.
Люди даже пишут целые статьи:
Именно здесь Rust жертвует читабельностью ради безопасности.Кроме того, такие упражнения также могут привести к зацикливанию ссылок, которые застревают в памяти, потому что.
никакой сборщик мусора их не удалит. Я не писал рабочий код на Rust, поэтому мне сложно сказать, насколько такие сложности усложняют жизнь.
Было бы интересно получить комментарии практикующих инженеров.
Сложность обучения
Длительный процесс изучения Rust во многом вытекает из предыдущего раздела.Прежде чем вообще что-либо написать, вам придется потратить время на освоение ключевой концепции управления памятью, потому что.
она пронизывает каждую строку.
Например, на простейший список у меня ушло пару вечеров, а на Котлине то же самое можно написать за 10 минут, несмотря на то, что это не мой рабочий язык.
Кроме того, многие распространенные подходы к написанию алгоритмов или структур данных в Rust будут выглядеть по-другому или вообще не работать.
Те.
при переходе на него потребуется более глубокая перестройка мышления; просто освоить синтаксис будет недостаточно.
Это далеко не JavaScript, который всё проглотит и всё потерпит. Я думаю, что Rust никогда не станет языком, на котором детей учат в школах программирования.
Даже у C/C++ в этом отношении больше шансов.
В конце концов Идея управления памятью во время компиляции мне показалась очень интересной.
У меня нет опыта работы с C/C++, поэтому я не буду сравнивать его с умным указателем.
Синтаксис в целом приятный и нет ничего лишнего.
Я критиковал Rust за сложность реализации графовых структур данных, но подозреваю, что это особенность всех языков программирования, не поддерживающих GC. Возможно, сравнение с Котлином было не совсем справедливым.
ДЕЛАТЬ В этой статье я вообще не затронул многопоточность; Я думаю, это отдельная большая тема.
Есть также планы написать какую-то структуру данных или алгоритм, более сложный, чем список; если у вас есть идеи, поделитесь ими в комментариях.
Было бы интересно узнать, какие типы приложений вообще пишутся на Rust. Читать Если вас интересует Rust, вот несколько ссылок:
- Программирование на Rust: быстрая и безопасная разработка систем - хорошая книга, есть и в электронной версии.
- Документация по ржавчине — официальная документация, есть примеры
- Идиоматический код Rust — список статей
- ruRust/easy И ruRust/общее — Гиттер-каналы
- р/ржавчина/ — Реддит
Я узнал много полезного для себя.
Исправлены неточности и опечатки, добавлены ссылки.
Я думаю, такие дискуссии во многом способствуют изучению новых технологий.
В опросе могут участвовать только зарегистрированные пользователи.
Войти , Пожалуйста.
Как вы думаете, стоит ли переходить на Rust? 39,65% Да, из языков низкого уровня (C/C++) 205 16,25% Да, из языков высокого уровня (Java/C#/Ruby/.
) 84 22,63% Да, может заменить любой язык 117 21,47% Нет, идти вообще не стоит 111 Проголосовали 517 пользователей.
190 пользователей воздержались.
Теги: #программирование #Rust #обучение программированию #обучение программированию
-
Игры Для Маленьких Девочек И Одевалки
19 Oct, 24 -
Mark Gauntlet V4.2: Инструкция По Созданию
19 Oct, 24 -
Космическая Гонка Между Ссср И Сша
19 Oct, 24 -
Пневмоплан – Будущее Белорусского Транспорта
19 Oct, 24 -
Зарядка Электромобилей С Поверхности Дороги
19 Oct, 24 -
Чтобы Не Пахнуть Геем
19 Oct, 24 -
Нло Упал В Красноярской Тайге
19 Oct, 24