我定义了一个特征Foo
,为[u32]
实现了这个特征,并编写了一个函数bar
,将这个特征作为参数(playground):
trait Foo {
fn foo(&self) -> u32;
}
impl Foo for [u32] {
fn foo(&self) -> u32 {
self[0]
}
}
fn bar<T>(f: &T) -> u32
where
T: Foo,
{
f.foo() + 1
}
fn main() {
let f: &[u32] = &[42];
bar(f);
}
这不会编译,因为bar
隐含地期望其参数为Sized
:
error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied
--> src/main.rs:20:5
|
20 | bar(f);
| ^^^ `[u32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u32]`
note: required by `bar`
--> src/main.rs:11:1
|
11 | / fn bar<T>(f: &T) -> u32
12 | | where
13 | | T: Foo,
14 | | {
15 | | f.foo() + 1
16 | | }
| |_^
我可以使用T: Foo + ?Sized
修复它,但是我必须为每个函数执行此操作,期待Foo
,这很痛苦......
我是否可以一劳永逸地声明Foo
的实施不应该是Sized
?我在第1行尝试了trait Foo: ?Sized
,但编译器抱怨它。
此问题与Trait implementing Sized不同。在那个问题中,移动了Foo
参数,因此编译器想要在编译时知道它的大小是正常的。在我的例子中,参数是一个引用,因此它不会需要来调整大小 - 但是除非明确告知(使用+ ?Sized
),否则编译器仍会隐式地假设它。对于这个特殊的特征,我想改变的是这个隐含的假设。
答案 0 :(得分:2)
trait Foo: ?Sized
?当你说
Foo
Sized
为Foo
时,你就会把真相隐藏起来。是的,每个Sized
都是[u32]
,但实际上每种类型在某些时候都有给定的大小。真正重要的信息是,你并不是说这个大小是多少。
在这种情况下,您要求大小error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied
|
| impl Foo for [u32] {
| ^^^ `[u32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u32]`
:
T
有关详细信息,请参阅this answer的Trait implementing Sized。
Sized
不合格,因为我们只有参考?让我再次引用this answer来自Why does a reference to a trait in a generic function have to implement Sized
?
默认情况下,函数上的所有泛型类型隐式绑定
明确选择退出该要求?Sized
,无论它们如何使用。您需要使用fn bar<T>(f: &T) -> u32 where T: Foo + ?Sized, { f.foo() + 1 }
这将解决您的问题:
Foo
还可以为&[u32]
实施impl<'a> Foo for &'a [u32] {
fn foo(&self) -> u32 {
self[0]
}
}
fn bar<T>(f: T) -> u32
where
T: Foo,
{
f.foo() + 1
}
:
Foo
在这种特殊情况下,您甚至可以概括Vec
的实现,它可以用于impl<T: AsRef<[u32]>> Foo for T {
fn foo(&self) -> u32 {
self.as_ref()[0]
}
}
和数组以及对这些类型的引用:
bar
使用新的impl Trait语法,fn bar(f: impl Foo) -> u32 {
f.foo() + 1
}
可以在最后两种情况下缩短为
\t