我准备通过一个名为new
的构造方法来存储它作为参数。
结构类型的特征在此处作为参数给出:
渲染器 .RS
use super::shapes::Shape;
pub struct Renderer;
impl Renderer{
pub fn set_shape<T : Shape>(&self, shape: T) -> T::Builder{
T::Builder::new(shape)
}
}
然后将调用相关类型指定的Builder
的构造函数
shapebuilder.rs
use super::shapes::Shape;
use super::shapes::Rectangle;
pub trait ShapeBuilder{
fn new<T:Shape>(shape: T) -> Self;
}
pub struct RectangleBuilder{
shape: Shape<Builder=RectangleBuilder>
}
impl ShapeBuilder for RectangleBuilder{
fn new<T:Shape>(shape: T) -> Self{
RectangleBuilder{
shape: shape as Rectangle
}
}
}
此时我已经想要指出编译器输出
compiler_output
error[E0277]: the trait bound `shapes::Shape<Builder=shapebuilder::RectangleBuilder> + 'static: std::marker::Sized` is not satisfied
--> shapes.rs:14:6
|
14 | impl Shape for Rectangle{
| ^^^^^
|
= note: `shapes::Shape<Builder=shapebuilder::RectangleBuilder> + 'static` does not have a constant size known at compile-time
= note: required because it appears within the type `shapebuilder::RectangleBuilder`
= note: required by `shapes::Shape`
error: aborting due to previous error
我在SO上发现了类似的问题,这些问题讲述了拳击事件。我尝试将每个参数类型设置为Box来解决问题。装箱就像这样shape: Box<T>
。没有成功。我需要装箱吗?我理解编译器无法解析特征大小的问题,因为特定/具体结构类型可以根据其字段/属性具有不同的大小。我仍然无法找到解决方案。希望它是微不足道的。
shapes.rs
use super::shapebuilder::ShapeBuilder;
use super::shapebuilder::RectangleBuilder;
pub trait Shape{
type Builder: ShapeBuilder;
}
#[derive(Clone, Copy)]
pub struct Rectangle{
pub height: usize,
pub width: usize,
}
impl Shape for Rectangle{
type Builder = RectangleBuilder;
}
lib.rs
pub mod renderer;
mod shapes;
mod shapebuilder;
答案 0 :(得分:6)
好吧,编译器并没有真正指出错误的来源。问题出在这里:
pub struct RectangleBuilder {
shape: Shape<Builder=RectangleBuilder>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is an unsized type!
}
Shape
是一个特征,并将其用作类型会产生一个未大小的类型。我们可以将其设置为修复此错误:
pub struct RectangleBuilder {
shape: Box<Shape<Builder=RectangleBuilder>>
}
但是,那么我们如何处理演员呢?
impl ShapeBuilder for RectangleBuilder {
fn new<T: Shape>(shape: T) -> Self {
RectangleBuilder {
shape: shape as Rectangle
// ^^^^^^^^^^^^^^^^^^ can't cast a generic type!
}
}
}
如果RectangleBuilder
确实准备好接受其Shape
为Builder
的任何RectangleBuilder
,那么让我们删除演员并在必要时添加适当的约束。
pub mod renderer {
use super::shapes::Shape;
use super::shapebuilder::ShapeBuilder;
pub struct Renderer;
impl Renderer {
pub fn set_shape<T: Shape + 'static>(&self, shape: T) -> T::Builder {
T::Builder::new(shape)
}
}
}
mod shapes {
use super::shapebuilder::ShapeBuilder;
use super::shapebuilder::RectangleBuilder;
pub trait Shape {
type Builder: ShapeBuilder;
}
#[derive(Clone, Copy)]
pub struct Rectangle {
pub height: usize,
pub width: usize,
}
impl Shape for Rectangle {
type Builder = RectangleBuilder;
}
}
mod shapebuilder {
use super::shapes::Shape;
pub trait ShapeBuilder: Sized {
fn new<T: Shape<Builder=Self> + 'static>(shape: T) -> Self;
}
pub struct RectangleBuilder {
shape: Box<Shape<Builder=RectangleBuilder> + 'static>,
}
impl ShapeBuilder for RectangleBuilder {
fn new<T: Shape<Builder=Self> + 'static>(shape: T) -> Self {
RectangleBuilder {
shape: Box::new(shape)
}
}
}
}
'static
绑定限制了可以存储在特定Shape
实例中的引用。 'static
表示实现不能包含引用,除非它们具有'static
生存期。
但是,如果您需要在Rectangle
中使用RectangleBuilder
的字段,那么RectangleBuilder
应该只接受Rectangle
,而不是任何形状。我们可以再次使用相关类型来表达这一点。
pub mod renderer {
use super::shapes::Shape;
use super::shapebuilder::ShapeBuilder;
pub struct Renderer;
impl Renderer {
pub fn set_shape<T: Shape>(&self, shape: T) -> T::Builder {
T::Builder::new(shape)
}
}
}
mod shapes {
use super::shapebuilder::ShapeBuilder;
use super::shapebuilder::RectangleBuilder;
pub trait Shape {
type Builder: ShapeBuilder<Shape=Self>;
}
#[derive(Clone, Copy)]
pub struct Rectangle {
pub height: usize,
pub width: usize,
}
impl Shape for Rectangle {
type Builder = RectangleBuilder;
}
}
mod shapebuilder {
use super::shapes::Shape;
use super::shapes::Rectangle;
pub trait ShapeBuilder: Sized {
type Shape: Shape + ?Sized;
fn new(shape: Self::Shape) -> Self;
}
pub struct RectangleBuilder {
shape: Rectangle,
}
impl ShapeBuilder for RectangleBuilder {
type Shape = Rectangle;
fn new(shape: Self::Shape) -> Self {
RectangleBuilder {
shape: shape
}
}
}
}
在ShapeBuilder
中,我们添加了一个Shape
关联类型,用于指定每个Shape
将运行的ShapeBuilder
类型。 ShapeBuilder::new
现在使用此关联类型而不是类型参数来指定其操作数的类型。请注意,需要+ ?Sized
绑定,因为否则存在隐式+ Sized
绑定,并且Rust抱怨Shape
并不暗示Sized
。解决此问题的另一种方法是将: Sized
添加到Shape
的定义中。
pub trait Shape: Sized {
type Builder: ShapeBuilder<Shape=Self>;
}