Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Rust > ООП на Rust


Автор: JoeUser 10.03.18, 11:26
Приветствую!

Решил ознакомится с Rust, но не заметил там "нативной" поддержки ООП. Тем не менее, конструкции языка позволяют применять инструментарий ООП. Нашел неплохую статью про это. Но увы, цельного примера я там не нашел, все расписывалось кусками. А хотелось бы в качестве резюме - полноценный пример.

Кому не лениво, и кто в теме, прошу составленный мною синтетический пример на C++ перевести на Rust:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    #include <iostream>
    #include <vector>
     
    // *****************************************************************************
     
    class Figure {
      public:
        virtual double Area() = 0;
        void PrintName() {
          std::cout << "Фигура = " << Name() << " ";
        }
      private:
        virtual std::string Name() = 0;
    };
     
    // *****************************************************************************
     
    class Rectangle: public Figure {
      public:
        explicit Rectangle(double h, double w): H(h), W(w) {}
        double Area() override {
          return H*W;      
        }
      private:
        double H,W;
        std::string Name() override {
          return "Прямоугольник";
        }
    };
     
    // *****************************************************************************
     
    class Square: public Rectangle {
      public:
        explicit Square(double l): Rectangle (l,l) {}
      private:
        std::string Name() override {
          return "Квадрат";
        }
    };
     
    // *****************************************************************************
     
    class Ellipse: public Rectangle {
      public:
        explicit Ellipse(double a, double b): Rectangle (a,b) {}
        double Area() override {
          return Rectangle::Area()*3.1415;      
        }
      private:
        std::string Name() override {
          return "Эллипс";
        }
    };
     
    // *****************************************************************************
     
    int main() {
      std::vector<Figure*> V;
      V.push_back(new Rectangle(2,3));
      V.push_back(new Square(4));
      V.push_back(new Ellipse(2,3));
      for(const auto &i:V) {
        i->PrintName();
        std::cout << ", площадь: " << i->Area() << std::endl;
        delete i;
      }
      return 0;
    }


Пока не пойму, как в Rust реализовать абстрактный класс, виртуальный метод, и как работать с перекрытием методов?

Автор: korvin 10.03.18, 13:56
Цитата JoeUser @
Но увы, цельного примера я там не нашел, все расписывалось кусками.

Так включи воображение и собери цельный пример. =) Ну как-то так, например:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    use std::io::stdin;
    use std::io::BufRead;
    use std::io::BufReader;
     
    mod figures {
     
        pub trait Figure {
            fn area(&self) -> f64;
            fn printName(&self) {
                print!("Figure = {} ", self.name());
            }
            fn name(&self) -> &'static str;
        }
     
        pub struct Rectangle {
            w: f64,
            h: f64,
        }
     
        impl Rectangle {
            pub fn new(width: f64, height: f64) -> Rectangle {
                Rectangle { w: width, h: height }
            }
        }
     
        impl Figure for Rectangle {
            fn name(&self) -> &'static str {
                "Rectangle"
            }
            fn area(&self) -> f64 {
                self.h * self.w
            }
        }
     
        pub struct Square {
            rectangle: Rectangle,
        }
     
        impl Square {
            pub fn new(size: f64) -> Square {
                Square { rectangle: Rectangle { w: size, h: size } }
            }
        }
     
        impl Figure for Square {
            fn name(&self) -> &'static str {
                "Square"
            }
            fn area(&self) -> f64 {
                self.rectangle.area()
            }
        }
     
        pub struct Ellipse {
            rectangle: Rectangle,
        }
     
        impl Ellipse {
            pub fn new(a: f64, b: f64) -> Ellipse {
                Ellipse { rectangle: Rectangle { w: a, h: b } }
            }
        }
     
        impl Figure for Ellipse {
            fn name(&self) -> &'static str {
                "Ellipse"
            }
            fn area(&self) -> f64 {
                self.rectangle.area() * 3.1415
            }
        }
    }
     
    fn main() {
        use figures::{Figure, Rectangle, Square, Ellipse};
        let v: [&Figure; 3] = [
            &Rectangle::new(2.0, 3.0),
            &Square::new(4.0),
            &Ellipse::new(2.0, 3.0)
            ];
        for i in v.iter() {
            i.printName();
            println!(", area: {}", i.area());
        }
    }

Автор: JoeUser 10.03.18, 14:04
Цитата korvin @
Так включи воображение

Это после включения обучения обычно делается :lol:

Автор: korvin 10.03.18, 14:12
Цитата JoeUser @
Это после включения обучения обычно делается

ХЗ, никакое обучение не проходил, раст видел только мельком, по статье и паре небольших статеек Rust by Example (чтобы синтаксические мелочи подсмотреть), слепил то что слепилось. =)

Автор: JoeUser 10.03.18, 14:34
Ну не спорю - кросава! :lol:

Автор: OpenGL 10.03.18, 20:38
Цитата JoeUser @
Пока не пойму, как в Rust реализовать абстрактный класс, виртуальный метод, и как работать с перекрытием методов?

Виртуальные методы делаются trait-ами, как в примере выше. Абстрактный класс сделать нельзя - trait содержит только методы, но не поля, т.е. они ближе к интерфейсам, чем к абстрактому классу. Динамический полиморфизм делается в точности как в плюсах - через указатель/ссылку на базу(trait). Например, если переписать пример korvin-а со ссылок на указатели (класс Box - полный аналог std::unique_ptr из плюсов), то объявление массива v в main будет таким:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        let v: Vec<Box<Figure>> = vec![
            Box::new(Rectangle::new(2.0, 3.0)),
            Box::new(Square::new(4.0)),
            Box::new(Ellipse::new(2.0, 3.0)),
        ];

Автор: JoeUser 11.03.18, 07:04
korvin, OpenGL, если я не ошибаюсь - в ваших кодах, в конце, заполнение вектора идет путем инициализации при объявлении. А нужно было добавлением. Но это так - мелочи. Просто маленькое несоответствие. Ваш вариант скорее всего бы соответствовал этому куску кода нс C++:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
          std::vector<Figure*> V = {
            new Rectangle(2,3),
            new Square(4),
            new Ellipse(2,3)
          };

Автор: korvin 11.03.18, 10:54
Цитата JoeUser @
если я не ошибаюсь - в ваших кодах, в конце, заполнение вектора идет путем инициализации при объявлении. А нужно было добавлением.

Это не относилось к вопросу, сделал так как было в примерах в статьях. Ты как-то вяло знакомишься с Rust, мог бы легко сам нагуглить.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ...
    use std::boxed::Box;
    use std::vec::Vec;
     
    ...
     
    fn main() {
        use figures::{Figure, Rectangle, Square, Ellipse};
        let mut v: Vec<Box<Figure>> = Vec::with_capacity(4);
        v.push(Box::new(Rectangle::new(2.0, 3.0)));
        v.push(Box::new(Square::new(4.0)));
        v.push(Box::new(Ellipse::new(2.0, 3.0)));
        for i in &v {
            i.printName();
            println!(", area: {}", i.area());
        }
    }

https://ideone.com/BGynKV

Автор: JoeUser 11.03.18, 17:10
Цитата korvin @
ы как-то вяло знакомишься с Rust

Еще раз - пасип. Да. Есть такое - вяло, мотивации немного недостаточно.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)