【问题标题】:'static: std::marker::Sized` is not satisfied - do I need to Box?'static: std::marker::Sized` 不满意 - 我需要 Box 吗?
【发布时间】:2016-09-10 08:22:39
【问题描述】:

我即将给出一个 trait 作为参数,通过一个名为 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
        }
    }
}

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

编译器输出

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 上发现了类似的问题,其中介绍了有关拳击的一些信息。我尝试将每个参数类型装箱以解决问题。像这样装箱shape: Box&lt;T&gt;。没有成功。我需要装箱吗?我理解编译器无法解决特征大小的问题,因为特定/具体的结构类型可能具有不同的大小,具体取决于它们的字段/属性。我仍然无法找到解决方案。希望它是微不足道的。


为了完整性而列出的未涉及的模块(我认为)

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;

【问题讨论】:

  • 这是你能做到的最小的例子吗?尝试找出具体问题,这将使您和我们都更清楚。
  • renderer.rs 和 shapebuilder.rs 已经尽可能小,并且是唯一的重要信息。以标题 NOT involed modules... 开头的内容 - 正如我所提到的 - 只是为了完整性,因为人们在另一个问题上要求所有模块自己编译和测试。请务必先阅读所有标题。
  • 我认为您没有正确理解我的观点 - 您当前的代码示例不是最小的并且包含从您的其他文件中导入的内容。为了使您的问题更清楚,您应该找到导致问题的代码部分,并完全摆脱其余部分,以制作一个仍然存在相同问题的更简单的示例。就目前而言,我需要将您的所有文件和目录结构复制到一个项目中,以重现您的问题,如果您进一步隔离问题,则没有必要这样做。
  • 嗯,你是对的 - 我正在花时间用一个更有针对性的例子来更新这个问题。
  • 现在让代码更简单了——我更喜欢这种方式,谢谢

标签: memory constructor rust traits


【解决方案1】:

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

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 确实准备好接受任何Builder 为RectangleBuilder 的Shape,那么让我们删除强制转换并在必要时添加适当的约束。

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 生命周期。

但是,如果您需要在RectangleBuilder 中使用Rectangle 的字段,那么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
            }
        }
    }
}

在ShapeBuilder 中,我们添加了一个Shape 关联类型,用于指定每个ShapeBuilder 将操作的Shape 的类型。 ShapeBuilder::new 现在使用此关联类型而不是类型参数来指定其操作数的类型。请注意,+ ?Sized 绑定是必需的,否则会有一个隐含的 + Sized 绑定,Rust 抱怨 Shape 并不意味着 Sized。解决此问题的另一种方法是将: Sized 添加到Shape 的定义中。

pub trait Shape: Sized {
    type Builder: ShapeBuilder<Shape=Self>;
}

【讨论】:

  • 哇...这非常明确。 Rust 确实需要非常明确地声明事物。作为一名 Java 开发人员,我很难考虑这一切——但我很高兴 Rust 以这种方式工作。让我了解代码如何更好地工作。将测试此解决方案并将其标记为尽快回答。谢谢
猜你喜欢
  • 2018-12-29
  • 2015-06-05
  • 1970-01-01
  • 2016-09-12
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
相关资源
最近更新 更多