特质实施大小

joj*_*ojo 13 rust

我知道特征和切片是未分级的,即在编译时不可能知道它们的大小,例如任何类型都可以实现特征,但是该类型可能没有大小.

不过,这个示例代码是不是意味着每个实现特征的类型都Foo需要实现Sized呢?

trait Foo: Sized {}

struct Bar(i64);

impl Foo for Bar {}
Run Code Online (Sandbox Code Playgroud)

如果是这样,为什么这不起作用?

impl From<Foo> for Bar {
    fn from(foo: Foo) -> Bar {
        Bar(64)
    }
}
Run Code Online (Sandbox Code Playgroud)
error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfied
 --> src/main.rs:7:6
  |
7 | impl From<Foo> for Bar {
  |      ^^^^^^^^^ `Foo + 'static` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static`
Run Code Online (Sandbox Code Playgroud)

我想向库的使用者提供一个类型(让我们命名Bar),并且可以转换为Bar实现特定特征的任何其他类型(让我们命名Foo).

Foo通过引用而不是值来解决它,但我不确定为什么编译器会抱怨实现者是否需要它Sized.

mdu*_*dup 11

为什么不起作用?

当你说每一个Foo都是Sized,你就是在向自己隐瞒真相.是的,每个Foo都是,Sized但实际上每种类型在某些时候都有给定的大小.真正重要的信息是你没有说这个尺寸是多少.想象一下,如果Bar(i64)Foo,但Baz(i8)同样Foo如此(它们都是Sized,对吗?)你确定的大小Foo是多少?是8字节还是1字节长?编译器在尝试为您的函数生成代码时会询问此问题from(foo: Foo).通常,Sized在语法中使用"maybe"-style ?Sized,表示在编译时类型大小可能是未知的.

怎么解决?

通常你会丢弃: Sized部分,并使用以下语法,这实际上是一种C++模板; 当给定具有给定大小的具体类型时,它为编译器提供草图以编写实际代码.

trait Foo {}

struct Bar(i64);

impl Foo for Bar {}

impl<F: Foo> From<F> for Bar {
    fn from(foo: F) -> Bar {
        Bar(64)
    }
}
Run Code Online (Sandbox Code Playgroud)

(这将仍然错误基础上的事实,你不能重新实现From,因为的std箱子,但它没有涉及到你原来的问题.)

您还可以在&Foo函数的参数中使用引用特征对象语法.这会将您的调用从静态调度转换为动态调度(在此处阅读更多内容),但您不能在此处执行此操作,因为签名是由特征强加的.