我知道特征和切片的大小是不确定的,即在编译时不可能知道它们的大小,例如任何类型都可以实现特征,但该类型可能无法调整大小。
然而,这个示例代码是否意味着每个实现特征的类型Foo
需要实施Sized
too?
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
.
为什么不起作用?
当你说每一个Foo
is Sized
,你有点向自己隐瞒了真相。是的,每个Foo
is Sized
但实际上每种类型在某个时刻都有给定的大小。真正重要的信息是你没有说这个尺寸是多少。想象一下如果Bar(i64)
is Foo
, but Baz(i8)
is 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 crate https://stackoverflow.com/q/37347311/155423,但这与你原来的问题无关。)
您还可以使用参考特征对象&Foo
函数参数中的语法。这会将您的调用从静态调度转换为动态调度(在这里阅读更多内容 http://doc.rust-lang.org/1.0.0-beta/book/static-and-dynamic-dispatch.html)但你不能在这里这样做,因为签名是由特征强加的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)