【问题标题】:Returning a generic type through an associated type通过关联类型返回泛型类型
【发布时间】:2016-09-07 05:38:29
【问题描述】:

我尝试做一些更通用的事情,但在尝试关联类型时失败了。 Given 是一个 Shape 特征和一个 Renderer 类型,它试图为特定类型的形状返回一个 Builder

形状

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

pub trait Shape{
    type Builder : ShapeBuilder;
}

impl Shape for Rectangle{
    type Builder = RectangleBuilder;
}

建造者

pub trait ShapeBuilder{
    type Renderer: ShapeRenderer;
    fn set_origin() -> Self::Renderer;
}

pub struct RectangleBuilder;

impl ShapeBuilder for RectangleBuilder{
    type Renderer = RectangleRenderer;
    fn set_origin() -> Self::Renderer{
        RectangleRenderer
    }
}

渲染器

pub struct Renderer<'a>{
    canvas:&'a mut Canvas
}

impl <'a>Renderer<'a>{
    pub fn new(canvas:&'a mut Canvas) -> Renderer {
        Renderer{
            canvas: canvas
        }
    }
    pub fn set_shape<T: Shape>(&self, shape: T) -> T::Builder{
        // trying to return the specific builder through shape::Builder
        // or something like that
    }
}

我想要实现的是set_shape 方法将返回RectangleBuilder 如果给定的shape 的类型是Rectangle

【问题讨论】:

  • 构建器是否需要参数来初始化新实例,或者它们是否应该可以在没有参数的情况下构造?
  • 其实是的——位是某种存根实现——首先要实现从渲染器到返回构建器的转换。您可能已经意识到我在这里尝试创建构建器模式。
  • 我认为我的第一条评论措辞不正确。为了构造一个builder,你需要参数吗,还是ShapeBuilder的每个实现都必须支持不带参数的构造?
  • 构造将没有参数。 set_origin() 的调用将是为构建器设置状态的唯一方法 - 实际呈现的形状的原点

标签: generics rust associated-types


【解决方案1】:

你需要在ShapeBuilder trait 中提供一个静态方法来实例化一个新的Self。静态方法只是没有self 参数的方法。

您可以直接添加方法:

pub trait ShapeBuilder: Sized {
    type Renderer: ShapeRenderer;

    fn new() -> Self;
    fn set_origin() -> Self::Renderer;
}

或者聪明点,将ShareBuilder 定义为Default 的子特征。

pub trait ShapeBuilder: Default {
    type Renderer: ShapeRenderer;

    fn set_origin() -> Self::Renderer;
}

然后,在set_shape 中,您可以实例化ShapeBuilder

impl <'a>Renderer<'a>{
    pub fn set_shape<T: Shape>(&self, shape: T) -> T::Builder {
        ShapeBuilder::new() // or Default::default()
    }
}

【讨论】:

  • 在这个例子中。当将Rectangle 对象设置为shape 参数时,ShapeBuilder::new() 会返回一个 RectangleBuilder 吗?因为我不明白如果返回的 Builder 是 RectangleBuilder 它是如何解决的,因为你只是返回 Self 而不是 Self::ShapeBuilder 之类的东西(我知道这是错误的语法)
  • @xetra11 是的。 Self 在特征定义中的意思是“实现这个特征的具体类型”。在这种情况下,RectangleBuilder。你也可以写T::Builder::new()&lt;T::Builder as ShapeBuilder&gt;::new() 而不是ShapeBuilder::new(),如果这对你来说更清楚的话。
  • 啊,好吧......所以如果我打电话给ShapeBuilder::new(),它就隐含地知道我在谈论T 的关联类型——你不这么认为吗? ,也是?
  • 如果你知道规则,这并不神奇。 :) 但说真的,这只是编译器从函数签名中指定的返回类型推断表达式类型的一个实例。再比如:如果你返回collect()的结果,那么编译器会根据函数的返回类型推断你想要的集合类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多