Черта обертывания в перечислении для разметки памяти и более простых обобщений? - PullRequest
0 голосов
/ 24 января 2020

Итак, в моем коде было что-то вроде следующего:

// Trait
trait Shape {
    fn area(&self) -> f32;
}

// Rect
struct Rect {
    width: f32,
    height: f32
}
impl Shape for Rect {
    fn area(&self) -> f32 {
        self.width * self.height
    }
}

// Circle
struct Circle {
    radius: f32
}
impl Shape for Circle {
    fn area(&self) -> f32 {
        self.radius * self.radius * std::f32::consts::PI
    }
}

// usage
fn use_shapes(shapes: Vec<Box<dyn Shape>>) {
    // ...
}

И мне действительно не нравился Box<dyn ...>, как по производительности, так и потому, что он был грубым. Мои реализации моей черты были немногочисленны и явны, поэтому я чувствовал себя хорошим кандидатом на получение перечисления.

В процессе преобразования его в перечисление я наткнулся на следующую схему:

// Wrapper enum
enum ShapeEnum {
    Rect(Rect),
    Circle(Circle)
}
impl Shape for ShapeEnum {
    fn area(&self) -> f32 {
        match self {
            ShapeEnum::Rect(data) => data.area(),
            ShapeEnum::Circle(data) => data.area(),
        }
    }
}

// new usage
fn use_shapes(shapes: Vec<ShapeEnum>) {
    // ...
}

Это довольно аккуратно. Это также похоже на обман как-то. Он компилируется и работает, как и ожидалось, просто достаточно необычно, что я хотел посмотреть, есть ли какие-нибудь неожиданные недостатки / затраты / причуды, которых я сейчас не вижу?

Мне также интересно, из-за детерминированный c характер реализации перечисления, это будет хороший макрос? Автоматически генерирует перечисление вокруг признака и набора его разработчиков, который сам реализует признак так же, как версия dyn.

1 Ответ

2 голосов
/ 24 января 2020

Я хотел бы узнать, есть ли какие-нибудь неожиданные недостатки / затраты / причуды, которых я сейчас не вижу?

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

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

// Wrapper enum
enum ShapeEnum {
    Rect(Rect),
    Circle(Circle),
    Dynamic(Box<T: Shape>),
}

impl Shape for ShapeEnum {
    fn area(&self) -> f32 {
        match self {
            ShapeEnum::Rect(data) => data.area(),
            ShapeEnum::Circle(data) => data.area(),
            ShapeEnum::Dynamic::(data) => data.area(),
        }
    }
}

Мне также интересно, если бы из-за детерминированной c природы реализации перечисления это сделало бы хороший макрос? Автоматически генерирует перечисление вокруг признака и набора его разработчиков, который сам реализует признак так же, как версия dyn

Похоже, что клетка enum_dispatch делает почти точно это ,

Отказ от ответственности: я сам этим не пользовался.

...