수색…


소개

Rust는 대수적 데이터 유형이 관련 메소드를 가질 수 있으므로 오브젝트 지향적입니다.이를 사용하여 작업하는 방법을 알고있는 코드와 함께 저장된 데이터의 의미로 객체가됩니다.

그러나 Rust는 상속을지지하지 않으며 특성을 가진 구성을 선호합니다. 이것은 많은 OO 패턴이있는 그대로 작동하지 않고 수정되어야 함을 의미합니다. 일부는 전혀 부적합합니다.

형질과의 상속

Rust에는 구조체의 속성을 "상속받는"개념이 없습니다. 그 대신, 객체 들간의 관계를 디자인 할 때, 인터페이스 (Rust의 특성) 에 의해 정의 된 방식으로 기능을 수행합니다. 이렇게 하면 상속에 대한 구성 이보다 유용하고 더 큰 프로젝트로 쉽게 확장 될 수 있습니다.

다음은 Python에서 예제 상속을 사용하는 예제입니다.

class Animal:
    def speak(self):
        print("The " + self.animal_type + " said " + self.noise)

class Dog(Animal):
    def __init__(self):
        self.animal_type = 'dog'
        self.noise = 'woof'

이것을 녹스 (Rust)로 번역하기 위해서, 우리는 동물을 구성하는 것을 꺼내서 그 기능을 형질에 넣어야합니다.

trait Speaks {
     fn speak(&self);

     fn noise(&self) -> &str;
}

trait Animal {
    fn animal_type(&self) -> &str;
}

struct Dog {}

impl Animal for Dog {
    fn animal_type(&self) -> &str {
        "dog"
    }
}  

impl Speaks for Dog {
    fn speak(&self) {
        println!("The dog said {}", self.noise());
    }

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

fn main() {
    let dog = Dog {};
    dog.speak();
}

이 추상 부모 클래스를 두 개의 분리 된 구성 요소, 즉 구조체를 동물로 정의하는 부분과 말하는 부분으로 나누었습니다.

모든 개발자는 "The {animal}이 {noise}"형식의 문자열을 출력하는 논리를 다시 구현해야하기 때문에이 방법은 상당히 일대일이 아닙니다. Speak for Animal 구현 한 인터페이스를 약간 재 설계하면됩니다.

trait Speaks {
     fn speak(&self);
}

trait Animal {
    fn animal_type(&self) -> &str;
    fn noise(&self) -> &str;
}

impl<T> Speaks for T where T: Animal {
    fn speak(&self) {
        println!("The {} said {}", self.animal_type(), self.noise());
    }
}

struct Dog {}
struct Cat {}

impl Animal for Dog {
    fn animal_type(&self) -> &str {
        "dog"
    }
    
    fn noise(&self) -> &str {
        "woof"
    }
}

impl Animal for Cat {
    fn animal_type(&self) -> &str {
        "cat"
    }

    fn noise(&self) -> &str {
        "meow"
    }
}

fn main() {
    let dog = Dog {};
    let cat = Cat {};
    dog.speak();
    cat.speak();
}

이제는 동물이 소음을 내고 말하면서 단순히 동물 인 것을 구현합니다. 이것은 이전 방식과 파이썬 상속보다 훨씬 융통성이 있습니다. 당신은 추가하려는 경우 예를 들어, Human 다른 사운드를 가지고, 우리는 대신의 또 다른 구현 할 수 있습니다 speak 뭔가 Human :

trait Human {
    fn name(&self) -> &str;
    fn sentence(&self) -> &str;
}

struct Person {}

impl<T> Speaks for T where T: Human {
    fn speak(&self) {
        println!("{} said {}", self.name(), self.sentence());
    }
}

방문자 패턴

Java의 일반적인 Visitor 예제는 다음과 같습니다.

interface ShapeVisitor {
    void visit(Circle c);
    void visit(Rectangle r);
}

interface Shape {
    void accept(ShapeVisitor sv);
}

class Circle implements Shape {
    private Point center;
    private double radius;

    public Circle(Point center, double radius) {
        this.center = center;
        this.radius = radius;
    }

    public Point getCenter() { return center; }
    public double getRadius() { return radius; }

    @Override
    public void accept(ShapeVisitor sv) {
        sv.visit(this);
    }
}

class Rectangle implements Shape {
    private Point lowerLeftCorner;
    private Point upperRightCorner;

    public Rectangle(Point lowerLeftCorner, Point upperRightCorner) {
        this.lowerLeftCorner = lowerLeftCorner;
        this.upperRightCorner = upperRightCorner;
    }

    public double length() { ... }
    public double width() { ... }

    @Override
    public void accept(ShapeVisitor sv) {
        sv.visit(this);
    }
}

class AreaCalculator implements ShapeVisitor {
    private double area = 0.0;

    public double getArea() { return area; }

    public void visit(Circle c) {
        area = Math.PI * c.radius() * c.radius();
    }

    public void visit(Rectangle r) {
         area = r.length() * r.width();
    }
}

double computeArea(Shape s) {
    AreaCalculator ac = new AreaCalculator();
    s.accept(ac);
    return ac.getArea();
}

이것은 두 가지 방법으로 쉽게 Rust로 번역 할 수 있습니다.

첫 번째 방법은 런타임 다형성을 사용합니다.

trait ShapeVisitor {
    fn visit_circle(&mut self, c: &Circle);
    fn visit_rectangle(&mut self, r: &Rectangle);
}

trait Shape {
    fn accept(&self, sv: &mut ShapeVisitor);
}

struct Circle {
    center: Point,
    radius: f64,
}

struct Rectangle {
    lowerLeftCorner: Point,
    upperRightCorner: Point,
}

impl Shape for Circle {
    fn accept(&self, sv: &mut ShapeVisitor) {
        sv.visit_circle(self);
    }
}

impl Rectangle {
    fn length() -> double { ... }
    fn width() -> double { ... }
}

impl Shape for Rectangle {
    fn accept(&self, sv: &mut ShapeVisitor) {
        sv.visit_rectangle(self);
    }
}

fn computeArea(s: &Shape) -> f64 {
    struct AreaCalculator {
        area: f64,
    }

    impl ShapeVisitor for AreaCalculator {
        fn visit_circle(&mut self, c: &Circle) {
            self.area = std::f64::consts::PI * c.radius * c.radius;
        }
        fn visit_rectangle(&mut self, r: &Rectangle) {
            self.area = r.length() * r.width();
        }
    }
    
    let mut ac = AreaCalculator { area: 0.0 };
    s.accept(&mut ac);
    ac.area
}

두 번째 방법은 대신 컴파일 타임 다형성을 사용하지만 차이점 만 표시합니다.

trait Shape {
    fn accept<V: ShapeVisitor>(&self, sv: &mut V);
}

impl Shape for Circle {
    fn accept<V: ShapeVisitor>(&self, sv: &mut V) {
        // same body
    }
}

impl Shape for Rectangle {
    fn accept<V: ShapeVisitor>(&self, sv: &mut V) {
        // same body
    }
}

fn computeArea<S: Shape>(s: &S) -> f64 {
    // same body
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow