将 trait 中方法的返回类型绑定到实现该 trait 的类型

时间:2020-12-23 15:39:00

标签: generics methods rust traits self

我有一个特征 Vertex,我想要几个结构来实现。我想要求一个实现 trait 的结构有一个返回该结构的 Vector 的方法。所以实现看起来像这样。

struct Point {
    // ...
}

impl Vertex for Point {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self> {
        unimplemented!()
    }
}

这样你就可以像Point::from_byte_buffer(...)一样称呼它。但是,我不知道如何在特征中编写方法签名。这是我最好的猜测。

trait Vertex {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self>;
}

然而,这给了我一个错误,

the size for values of type `Self` cannot be known at compilation time

这有点意思,因为在这种情况下 Self 不是一个具体的类型。我想过做这样的事情,

trait Vertex {
    fn from_byte_buffer<V: Vertex>(buffer: &[u8]) -> Vec<V>;
}

但这与实现特征的具体类型无关。我需要使用关联类型吗?

2 个答案:

答案 0 :(得分:2)

所有 Rust trait 都有一个隐含的 ?Sized 界限,所以:

trait Trait {}

脱糖:

trait Trait where Self: ?Sized {}

这是默认完成的,因此可以将 trait 转换为 trait 对象。您可以通过在特征上设置显式 Sized 绑定来覆盖此默认值,例如

trait Trait: Sized {}

或者可选地在特定特征项上设置显式 Sized 绑定,例如

trait Trait {
    fn func() where Self: Sized {}
}

后一种方法的好处是您仍然可以将上述特征转换为特征对象(尽管您将无法调用该特定的 Sized 方法)。

将第一个解决方案应用于您的示例会产生:

trait Vertex: Sized {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self>;
}

struct Point;

impl Vertex for Point {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self> {
        todo!()
    }
}

playground

应用第二种解决方案产生:

trait Vertex {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self> where Self: Sized;
}

struct Point;

impl Vertex for Point {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self> {
        todo!()
    }
}

playground

两者都按照您的预期进行编译和工作。首先需要将 Self 标记为 Sized 的原因是因为 Vec 只能包含编译时已知大小的项目。

如果您想更彻底和深入地了解 Rust 中大小的工作原理,我建议您阅读 Sizedness in Rust(免责声明:我写的)。

答案 1 :(得分:0)

您可以将 Self 绑定为 Sized

trait Vertex where Self: Sized {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self>;
}

或者干脆

trait Vertex: Sized {
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self>;
}

因为 SelfVertex

编辑:或使用关联类型:

trait Vertex
where
    <Self as Vertex>::Inner: Sized
{
    type Inner;
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self::Inner>;
}

struct Point {
}

impl Vertex for Point {
    type Inner = Point;
    fn from_byte_buffer(buffer: &[u8]) -> Vec<Self::Inner> {
        vec![]
    }
}
相关问题