匹配实现特征的类型,从而返回它

xet*_*a11 0 traits pattern-matching rust

我正在尝试一些特定的构建器模式.请不要介意这里的设计 - 这是一个试用版.

我有一个Renderer产生方法的类型set_shape.给调用的参数类型应该实现空特征IsRenderable.然后,方法的登录应该在结构类型之间有所不同,Rectangle并且Circle两者都实现了IsRenderable特征.不要为返回类型而烦恼.

#[derive(Clone, Copy)]
pub struct Rectangle {
    pub origin: Point,
    pub height: usize,
    pub width: usize,
}

trait IsRenderable {}

impl IsRenderBuilder for Rectangle {}

impl<'a> Renderer<'a> {
    // logic that needs lifetime 'a
    pub fn set_shape<T: IsRenderable>(shape: T) -> Box<IsRenderBuilder> {
        match shape {
            _ => panic!("WTF!"),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情. PSEUDO:

match shape {
    Rectangle => return RectangleShapeBuilder,
    Circle => return CircleShapeBuilder,
    _ => panic!("WTF!"),
}
Run Code Online (Sandbox Code Playgroud)

Fra*_*gné 5

match您应该在IsRenderable特征上添加一个方法,而不是使用该方法,该方法返回特定实现者的相应构建器.

#[derive(Clone, Copy)]
pub struct Rectangle;

pub trait IsRenderable {
    fn new_builder(&self) -> Box<IsRenderBuilder>;
}

impl IsRenderable for Rectangle {
    fn new_builder(&self) -> Box<IsRenderBuilder> {
        Box::new(RectangleShapeBuilder)
    }
}

struct RectangleShapeBuilder;

pub trait IsRenderBuilder {}

impl IsRenderBuilder for RectangleShapeBuilder {}

pub fn set_shape<T: IsRenderable>(shape: T) -> Box<IsRenderBuilder> {
    shape.new_builder()
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用关联类型来避免装箱IsRenderBuilder:

#[derive(Clone, Copy)]
pub struct Rectangle;

pub trait IsRenderable {
    type Builder: IsRenderBuilder;

    fn new_builder(&self) -> Self::Builder;
}

impl IsRenderable for Rectangle {
    type Builder = RectangleShapeBuilder;

    fn new_builder(&self) -> Self::Builder {
        RectangleShapeBuilder
    }
}

pub struct RectangleShapeBuilder;

pub trait IsRenderBuilder {}

impl IsRenderBuilder for RectangleShapeBuilder {}

pub fn set_shape<T: IsRenderable>(shape: T) -> T::Builder {
    shape.new_builder()
}
Run Code Online (Sandbox Code Playgroud)

  • @LukasKalbertodt:我不认为名称冲突是一个问题,因为`T :: Builder`被静态地解析为"特征'IsRenderable`中的关联类型`Builder`",因为所有编译器都知道`T`是它实现了'IsRenderable`.Rust不像C++模板那样工作,其中依赖类型仅在模板实例化时解析.添加另一个特征绑定可能会导致歧义,但是当引发歧义时可以解决它,而不是直接使用重量级语法. (2认同)