我知道特征和切片是未分类的,即在编译时无法知道它们的大小,例如任何类型都可以实现特征,但该类型的大小可能不会。
然而,这个示例代码是否意味着实现特征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
所需要的。
答案 0 :(得分:11)
当你说每Foo
都是Sized
时,你就会把真相隐藏起来。是的,每个Foo
都是Sized
,但实际上每种类型在某些时候都有给定的大小。真正重要的信息是你没有说这个尺寸是多少。想象一下,如果Bar(i64)
是Foo
,但Baz(i8)
也是Foo
(它们都是Sized
,对吗?)您确定{{1} }} 成为?是8字节还是1字节长?编译器在尝试为您的函数Foo
生成代码时会询问此问题。通常,from(foo: Foo)
更像是使用语法Sized
的“可能”式,表示在编译时类型大小可能是未知的。
通常你会抛弃?Sized
部分,并使用以下语法,这实际上是一种C ++模板;当给定具有给定大小的具体类型时,它为编译器提供草图以编写实际代码。
: Sized
(still error the fact that you cannot reimplement From
because of the std
crate基于read more here,但与原始问题无关。)
您还可以在函数的参数中使用引用特征对象trait Foo {}
struct Bar(i64);
impl Foo for Bar {}
impl<F: Foo> From<F> for Bar {
fn from(foo: F) -> Bar {
Bar(64)
}
}
语法。这会将您的调用从静态调度转换为动态调度(this post),但您不能在此处执行此操作,因为签名是由特征强加的。
答案 1 :(得分:0)
Foo
特征要求实施者为Sized
。这并不意味着Foo
本身会有一个大小。你误解了第二个代码示例的语法,因此我不确定你实际上要做什么。你在找这个吗?
impl From<i64> for Bar {
fn from(val: i64) -> Bar {
Bar(val)
}
}
或者您想要一种从任何有符号整数构造Bar
的方法吗?
我们这里有一个XY problem。