🤓 ООП. Часть 7. Rust.



Меня несколько раз спрашивали подписчики, считаю ли я, что ООП как парадигма умирает?



Давайте я сразу отвечу на этот вопрос - нет, ОО по-прежнему очень актуальна. Хотя бы потому, что самые популярные в мире ЯП полностью или частично можно отнести к ОО парадигме. Хоть в ту же Java и добавили кучу физ из ФП, но классы и ОО по прежнему остаются главным структурным блоком этого ЯП. Более того, у нас вышло несколько новых ЯП с привычной ОО моделью, которые несмотря на свой юный возраст уже заняли свою значительную нишу. Речь тут, разумеется, идет про Kotlin и Swift.



Так что оставить панику. ОО сейчас актуальна, как и 30 лет назад. Но в ОО действительно есть много недостатков, которые закрываются паттернами. А в новых ЯП у нас появляется возможность взять самое лучше из мира ОО, но не брать плохое. Так и образовался пласт языков, которые я называю общим словом пост-ОО. Несмотря на общее название, языки этой группы могут сильно отличаться друг от друга. Объединяет их лишь то, что они отказались от традиционной Simula/Smalltalk ОО модели в пользу чего-то иного, но при этом сохранив определенные черты ОО языков. И вот сегодня речь пойдет про один из таких ЯП - Rust.



Rust очень интересный ЯП по многим аспектам, но в этих статьи мы разбираем языки на предмет реализации ОО модели. Однако, переде тем как сделать это, давайте посмотрим на прямых "родителей":



1. С. Да-да, именно C, а не С++. Rust перенял очень многое от своего знаменитого родственника. Более того, Rust имеет совместимость с C ABI, т.е. вы можете не только импортировать С библиотеки в программы на Rust, но и наоборот. Для этого в Rust даже существую специальные C-like структуры-данных: Union, CString и т.д.



2. Языки семейства ML (OCaml и Haskell): типизация, выведение типов, алгебраические типы, сопоставления с шаблонами, система характеристик, почти все конструкции являются выражениями.



3. Языки семейства Lisp. Макросы и мета-программирование.



4. Python. Да, именно так. Когда я начинал писать на Rust, у меня не проходило чувство дежавю по сравнению с Python. Тут и ассоциированные функции с явным self аргументом. Итераторы как определяющий элемент дизайна стандартной библиотеки. И много чего еще по мелочи.



В общем гремучая смесь из процедурных, функциональный и ОО языков. Так давайте ответим на вопрос, является ли Rust ОО языком? Скорее, нет.



- В Rust нет понятие класса или объекта со связанной с ней инкапсуляции данных и поведения.



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



fn main() {

let x = 2.0;



// Вызов метода через точку

let y = x.powi(3);

println!("2^3 = {}", y);



// Вызов метода через явную квалификацию

let z = f64::powi(x, 3);

println!("2^3 = {}", z);

}




Реализовать/добавить новое поведение можно для любой структуры, а не только ту, что создали вы. Т.е. накинуть "новых методов" числам не составляет труда, однако работает это не через механизм динамической диспетчеризации как в Smalltalk, а за счет статической компиляции.



trait Double {

fn double(self) -> Self;

}



impl Double for i32 {

fn double(self) -> i32 {

self * 2

}

}



fn main() {

let x: i32 = 5;



// Выглядит как новый метод, но это сахар для Double::double(x)

let result = x.double();

println!("Удвоенное значение {} равно {}", x, result);

}




Явная инкапсуляция данных есть, но только на уровне модулей/крейтов (пакетов).



- В Rust нет наследования реальных типов, но есть наследование характеристик.



Характеристика с точки зрения ОО похожа на интерфейсы Java. В них также определяется набор "методов/свойств" для реализующих их структуры, а также могут быть реализации по-умолчанию. Главное отличие от интерфейсов в том, что мы можем реализовать характеристику для любого типа, а не только для своего. Обратное также справедливо: мы можем реализовать стороннюю характеристику для своего типа.