'static:std :: marker :: Sized`不满意 - 我需要Box吗?

xet*_*a11 5 memory constructor traits rust

我将通过一个名为contructor的方法来提供一个特征作为参数来存储它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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此时我已经想要指出编译器输出

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
Run Code Online (Sandbox Code Playgroud)

我在这里发现了类似的问题,这些问题讲述了拳击事件.我尝试将每个参数类型设置为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;
}
Run Code Online (Sandbox Code Playgroud)

lib.rs

pub mod renderer;
mod shapes;
mod shapebuilder;
Run Code Online (Sandbox Code Playgroud)

Fra*_*gné 6

好吧,编译器并没有真正指出错误的来源.问题出在这里:

pub struct RectangleBuilder {
    shape: Shape<Builder=RectangleBuilder>
    //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is an unsized type!
}
Run Code Online (Sandbox Code Playgroud)

Shape是一个特征,并使用它作为一种类型产生一个unsized类型.我们可以用它来修复此错误:

pub struct RectangleBuilder {
    shape: Box<Shape<Builder=RectangleBuilder>>
}
Run Code Online (Sandbox Code Playgroud)

但那么,我们如何处理这里的演员呢?

impl ShapeBuilder for RectangleBuilder {
    fn new<T: Shape>(shape: T) -> Self {
        RectangleBuilder {
            shape: shape as Rectangle
            //     ^^^^^^^^^^^^^^^^^^ can't cast a generic type!
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果RectangleBuilder确实将准备接受任何ShapeBuilderRectangleBuilder,那么我们删除的演员和添加适当的约束在必要.

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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

'static绑定它限制可以存储在特定的参考Shape实例.'static意味着实现不能包含引用,除非它们具有'static生命周期.

但是,如果你需要使用Rectangle的字段RectangleBuilder,那么RectangleBuilder应该只接受Rectangles,而不是任何形状.我们可以再次使用相关类型来表达这一点.

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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ShapeBuilder,我们添加了一个Shape关联类型,指定Shape每个类型的ShapeBuilder操作类型.ShapeBuilder::new现在使用此关联类型而不是类型参数来指定其操作数的类型.请注意,+ ?Sized需要绑定,因为否则存在隐式+ Sized绑定,并且Rust抱怨Shape并不意味着Sized.另一种解决方法是添加: SizedShape定义中.

pub trait Shape: Sized {
    type Builder: ShapeBuilder<Shape=Self>;
}
Run Code Online (Sandbox Code Playgroud)

  • 哇......这很明确.Rust确实需要非常明确地声明事物.作为Java开发人员,我很难想到这一切 - 但我很高兴Rust以这种方式工作.让我理解代码如何更好地工作.要测试这个解决方案并将其标记为尽快回答.谢谢 (3认同)