LINUX.ORG.RU

Наследование в Rust

 , ,


1

8

Здравствуйте. Потихоньку изучаю Rust. Насколько я понял, пробежавшись по документации, в Rust ООП реализовано через struct и trait. Это так? Так вот, как реализовать наследование? Например есть следующий код:

struct Shape {
    x: f64,
    y: f64,
}

trait Circle: Shape {
    
}

trait Square: Shape {
    
}

Как мне в Circle после наследования от Shape создать поле radius? То есть что то типа

trait Circle: Shape {
    radius: f64,
}

Вообще было бы здорово, если бы кто-нибудь рассказал про ООП в Rust. Заранее спасибо большое :)

В Rust нет наследования. ООП в нем, в общем-то, тоже нет.

tailgunner
()

Вообще было бы здорово, если бы кто-нибудь рассказал про ООП в Rust.

В Rust нет наследования. ООП в нем, в общем-то, тоже нет.

ну как, здорово?

anonymous
()
Ответ на: комментарий от anonymous

Здорово постоянно узнавать что-то новое и развиваться. Троллинг твой не уместен.

TigranElGrande
() автор топика

Велосипедить только остается. Заменяешь наследование на композицию и иерархию trait'ов. Ж(

anonymous
()
Ответ на: комментарий от TigranElGrande

struct это данные (множество полей). trait это интерфейс (множество сигнатур функций). Ты можешь написать реализацию некоторого trait-а для некоторого типа (в том числе и для struct). Т.е. можешь создать сущность «данные + поведение».

ООП как такового (как в Java) нет. Но в принципе все задачи, которые ставятся перед ООП, в Rust решать можно.

Legioner
()
trait Shape {
    fn get_x(&self) -> f64;
    fn get_y(&self) -> f64;
}

struct ShapeData {
    x : f64,
    y : f64
}

impl Shape for ShapeData {
    fn get_x(&self) -> f64 {
        self.x
    }

    fn get_y(&self) -> f64 {
        self.y
    }
}

trait Circle : Shape {
    fn get_radius(&self) -> f64;
}

struct CircleData {
    parent : ShapeData,
    radius : f64
}

impl Shape for CircleData {
    fn get_x(&self) -> f64 {
        self.parent.get_x()
    }

    fn get_y(&self) -> f64 {
        self.parent.get_y()
    }
}
impl Circle for CircleData {
    fn get_radius(&self) -> f64 {
        self.radius
    }
}

fn main() {
    let base_shape: ShapeData = ShapeData{x: 0.0, y: 0.0};
    let circle: CircleData = CircleData{parent:ShapeData{x: 10.0, y: 10.0}, radius: 5.0};
}

Вот такое вот, блин, там «ООП». Ты бы еще про exceptions спросил=)

anonymous
()
Ответ на: комментарий от anonymous

Код оттуда:

trait Animal {
    // Static method signature; `Self` refers to the implementor type
    fn new(name: &'static str) -> Self;

    // Instance methods, only signatures
    fn name(&self) -> &'static str;
    fn noise(&self) -> &'static str;

    // A trait can provide default method definitions
    fn talk(&self) {
        // These definitions can access other methods declared in the same
        // trait
        println!("{} says {}", self.name(), self.noise());
    }
}

struct Dog { name: &'static str }

impl Dog {
    fn wag_tail(&self) {
        println!("{} wags tail", self.name);
    }
}

// Implement the `Animal` trait for `Dog`
impl Animal for Dog {
    // Replace `Self` with the implementor type: `Dog`
    fn new(name: &'static str) -> Dog {
        Dog { name: name }
    }

    fn name(&self) -> &'static str {
        self.name
    }

    fn noise(&self) -> &'static str {
        "woof!"
    }

    // Default trait methods can be overridden
    fn talk(&self) {
        // Traits methods can access the implementor methods
        self.wag_tail();

        println!("{} says {}", self.name, self.noise());
    }
}

struct Sheep { naked: bool, name: &'static str }

impl Sheep {
    fn is_naked(&self) -> bool {
        self.naked
    }

    fn shear(&mut self) {
        if self.is_naked() {
            // Implementor methods can use the implementor's trait methods
            println!("{} is already naked!", self.name());
        } else {
            println!("{} gets a haircut", self.name);

            self.talk();
            self.naked = true;
        }
    }
}

impl Animal for Sheep {
    fn new(name: &'static str) -> Sheep {
        Sheep { name: name, naked: false }
    }

    fn name(&self) -> &'static str {
        self.name
    }

    fn noise(&self) -> &'static str {
        if self.is_naked() {
            "baaah"
        } else {
            "baaaaaaaaaaaah"
        }
    }
}

fn main() {
    // Type annotation is necessary in this case
    let mut dolly: Sheep = Animal::new("Dolly");
    let spike: Dog = Animal::new("Spike");
    // TODO ^ Try removing the type annotations

    dolly.shear();

    spike.talk();
    dolly.talk();
}

anonymous
()
Ответ на: комментарий от anonymous

если разраб плюсов был под героином, то разрабы раста были под говнецом

anonymous
()
Ответ на: комментарий от anonymous

Адовый синтаксис. Аж подсветка слетела. И эти люди ещё ругают C++

anonymous
()
Ответ на: комментарий от quantum-troll

Ну ты же понимаешь, что этот пример демонстрирует сами типажи, а не их грамотное использование на практике?

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

(другой анонимус)

anonymous
()
Ответ на: комментарий от anonymous

Я имею в виду то, что пример с кошечками и собачками это одно, а использование инструментов на реальном коде — совсем другое. Поэтому книги вроде «Programming in ‹langname›» такие толстые.

quantum-troll
()
Ответ на: комментарий от quantum-troll

А мне вот кажется, что rust неюзабелен. Без ООП на определенном уровне тяжеловато большие проекты делать. Да и исключений нет. Синтаксис сопоставим с крестами. ХЗ чего они хотят добиться...

anonymous
()
Ответ на: комментарий от Dark_SavanT

Каким образом ты декомпозируешь систему на высоком уровне? Каким образом модифицируешь реализации, наследуя(в широком смысле слова) уже то, что реализовано(и отлажено) и переопределяя что-то в реализации интерфейсной части? Каким образом расширяешь функциональность? ООП без фанатизма - очень хорошая штука. Конечно, если начинать городить фабрики фабрик, инвертировать зависимости и инъектить зависимости, то да, будет ад. Но ведь это зависит от разработчиков...

anonymous
()
Ответ на: комментарий от anonymous

Синтаксис сопоставим с крестами.

Нет. Тут плохо читаемый ML-й синтаксис, и значит массы его не воспримут, в отличие как раз от С++, Java, C#.

anonymous
()
Ответ на: комментарий от quantum-troll

Согласен с Вами. Не понятно как на практике применять теорию.

TigranElGrande
() автор топика

Так вот, как реализовать наследование?

Пока никак, но разные варианты наследования обсуждаются. Язык развивается быстро, думаю скоро будет.

DarkEld3r
()
Ответ на: комментарий от anonymous

Без ООП на определенном уровне тяжеловато большие проекты делать.

Какие конкретно проблемы ты ожидаешь с Rust в больших проектах? В Rust что-то мешает применять принципы SOLID?

Да и исключений нет.

Большинство кодеров не может в exception-safe код. В типичном случае кодеры прямолинейно и бездумно используют guard-ы. Так что когда исключение на самом деле вылетает, программа приходит в неконсистентное логическое состояние. Покрытие таких сценариев юнит-тестами обычно околонулевое. В общем, исключения — это крайне неоднозначная штука; а если ты хочешь писать программы с упором на надежность, то скорее вредная, чем полезная.

Manhunt ☕☕
()
Последнее исправление: Manhunt (всего исправлений: 1)
Ответ на: комментарий от DarkEld3r

Язык развивается быстро, думаю скоро будет.

Даешь rust++ с ООП!

anonymous
()
Ответ на: комментарий от anonymous

Без ООП на определенном уровне тяжеловато большие проекты делать.

В чем именно трудности?

anonymous
()
Ответ на: комментарий от anonymous

Лол, сходи в википедию, посмотри, как на самом деле выглядят «нечитаемые» ML-и, и сравни с {}-нойзом из топика.

anonymous
()
Ответ на: комментарий от anonymous

Лол, сходи в википедию, посмотри, как на самом деле выглядят «нечитаемые» ML-и, и сравни с {}-нойзом из топика.

Это тебе надо сходить и ознакомиться с OCaml, например. Точно такие же {}.

anonymous
()
Ответ на: комментарий от anonymous

Анон, не тупи. Раст не ML ни разу. Раст - это си-подобная перловка в стиле «кот по клавиатуре погулял». Посмотри примеры по своей ссылке - насколько там код чище и проще того говна, что постят в примерах растоманы.

anonymous
()
Ответ на: комментарий от DarkEld3r

Пока никак, но разные варианты наследования обсуждаются.

А какие варианты? Мне понравилось, как в Scala сделано. Наверное, самая любимая реализация ООП. Но там тоже есть свои компромиссы для взаимодействия с Java, тут же можно было продумать все изначально...

anonymous
()
Ответ на: комментарий от Manhunt

В Rust что-то мешает применять принципы SOLID?

Отсутствие поддержки ООП, например=)

Большинство кодеров не может в exception-safe код.

Возможно, стоит подумать над улучшением механизма. В Java почему-то кодеры могут исключения.

В общем, исключения — это крайне неоднозначная штука; а если ты хочешь писать программы с упором на надежность, то скорее вредная, чем полезная.

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

anonymous
()
Ответ на: комментарий от anonymous

Раст не ML ни разу. Раст - это си-подобная перловка

Ну да, ну да. Алгебраически типы, pattern matching, вывод типов - всё это взято из Си.

tailgunner
()
Ответ на: комментарий от anonymous

В чем именно трудности?

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

anonymous
()
Ответ на: комментарий от tailgunner

У антоши синтаксис головного мозга. Лечится резекцией лобных долей и приобщением к физическому труду.

Manhunt ☕☕
()
Ответ на: комментарий от anonymous

Это большое число подсистем очень хорошо, как правило, ложиться на ОО-модель

Большое количество подсистем хорошо ложится на модель «интерфейс-реализация».

tailgunner
()
Ответ на: комментарий от anonymous

Ты путаешь модульность и ООП.

anonymous
()
Ответ на: комментарий от anonymous

Какие конкретно проблемы ты ожидаешь с Rust в больших проектах? В Rust что-то мешает применять принципы SOLID?

Отсутствие поддержки ООП, например=)

Что конкретно из solid не получается сделать?

Manhunt ☕☕
()
Ответ на: комментарий от anonymous

Это большое число подсистем очень хорошо, как правило, ложиться на ОО-модель. Мы легко можем заменять одни компоненты другими, добавлять новую функциональность, без ущерба для старого кода, очень большая часть кода переиспользуется и пр. и пр.

Это все спокойно делается с трейтами, не?

Manhunt ☕☕
()
Ответ на: комментарий от Manhunt

S

С этим ок

O

Тут проблемы, поскольку без наследования это делается только руками(реализация интерфейса + агрегирование).

L

В rust справедливо лишь в отношении интерфейсной части

I

Вот тут можно сказать даже отлично

D

Тут тоже очень даже неплохо

anonymous
()
Ответ на: комментарий от tailgunner

Большое количество подсистем хорошо ложится на модель «интерфейс-реализация».

Ага, еще, например, неплохо бы иметь модули/классы, открытые для расширения и закрытые для модификации... Этого в Rust нет. Нужно костылить, как в примерах кода выше.

anonymous
()
Ответ на: комментарий от Manhunt

В основном это касается O и частично L.

anonymous
()
Ответ на: комментарий от tailgunner

Алгебраически типы, pattern matching, вывод типов - всё это взято из Си.

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

anonymous
()
Ответ на: комментарий от tailgunner

Большое количество подсистем хорошо ложится на модель «интерфейс-реализация».

Но этого недостаточно. Нужно иметь простую возможность взять некоторый тип/модуль, немного его расширить, чуть модифицировать его реализацию и не только использовать в новом коде, но так же передавать в старый.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.