问题 特质实施大小


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

然而,这个示例代码不是指每个实现特征的类型 Foo 需要实施 Sized 太?

trait Foo: Sized {}

struct Bar(i64);

impl Foo for Bar {}

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

impl From<Foo> for Bar {
    fn from(foo: Foo) -> Bar {
        Bar(64)
    }
}
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`

我想向库的消费者提供一种类型(让我们给它命名 Bar)并使转换为 Bar 来自任何其他实现特定特征的类型(让我们来命名它) Foo)。

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


7978
2017-07-20 11:58


起源



答案:


为什么不起作用?

当你说每一个 Foo 是 Sized,你有点把事实隐藏起来给自己。是的,每一个 Foo 是 Sized 但实际上每种类型在某些时候都有给定的大小。真正重要的信息是你没有说这个尺寸是多少。想象一下,如果 Bar(i64) 是 Foo但是 Baz(i8) 是 Foo 同样(他们都是 Sized,对吗?)你决定了哪种尺寸 Foo 成为?它是8字节还是1字节长?编译器在尝试为您的函数生成代码时会询问此问题 from(foo: Foo)。通常情况下, Sized 而是用于“可能”式的语法 ?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)
    }
}

(这会 仍然是错误 基于 你不能重新实现的事实 From 因为 std 箱,但这与你原来的问题无关。)

您还可以使用参考特征对象 &Foo 函数参数的语法。这会将您的调用从静态调度转换为动态调度(在这里阅读更多)但你不能在这里这样做,因为签名是由特质强加的。


11
2017-07-20 12:21





Foo 特质需要实现者 Sized。这并不意味着 Foo 本身将有一个大小。您误解了第二个代码示例的语法,因此我不确定您实际上要做什么。你在找这个吗?

impl From<i64> for Bar {
    fn from(val: i64) -> Bar {
        Bar(val)
    }
}

或者你想要一种方法来构建一个 Bar 从任何有符号整数?

我们有一个 XY问题 这里。


0
2017-07-20 12:54