由于此错误的两个实例,以下代码将无法编译:
错误[E0277]:不满足特征限制
Self: std::marker::Sized
我不明白为什么在这个实例中需要Sized
,因为&self
和&Any
都是指针,并且操作不需要知道实现该实现的结构的大小trait,它只需要知道指针本身及其转换的类型,因为&self
在特征中实现时是通用的。
我认为这可能是编译器强制执行不必要约束的一个实例,我考虑过使用生锈的GitHub仓库提出问题,但我想我应该看看有没有人知道我去之前没有的东西提出问题。
use std::any::Any;
trait Component: Any {
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
替代方法是为实现此特征的结构提供as_any()
和as_any_mut()
所需的函数,但对于这些结构,实现将始终与此处显示的每个字符完全相同,导致几个相同的样板代码实例。
答案 0 :(得分:6)
动态大小的类型也可以实现特征。特别是,当您定义对象安全特征时,编译器还会定义一个动态大小的类型,其名称与特征相同,这样您就可以使用&Component
等对象类型。
&Component
或&Any
等对象类型不仅仅是普通指针;他们是胖指针。胖指针结合了指向数据的指针和另一个数据:对于对象类型,它是指向vtable的指针;对于切片,它是切片的长度。
当从常规指针(例如&Button
)转换为对象类型时,编译器静态地知道将哪个vtable放入胖指针(例如Button
的{{1}}的vtable })。另一方面,Rust不支持从对象类型转换为另一种对象类型(例如从Any
到&Component
),因为对象中没有足够的数据来初始化新的胖指针。这就是编译器将此注释添加到错误消息中的原因:
&Any
有两种方法可以解决这个问题:
要求实施= note: required for the cast to the object type `std::any::Any + 'static`
的所有类型都为Component
:
Sized
这导致您无法使用trait Component: Any + Sized {
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
或&Component
等对象类型。
仅当Box<Component>
为as_any
时,as_any_mut
和Self
方法才可用:
Sized
这样,您仍然可以使用特征的对象类型,但是您无法在其上调用trait Component: Any {
fn as_any(&self) -> &Any
where Self: Sized
{
self
}
fn as_any_mut(&mut self) -> &mut Any
where Self: Sized
{
self
}
}
和as_any
。
答案 1 :(得分:4)
我发现我认为这是一个不需要新编译器功能的出色解决方案。
pub trait Component {
// ...
}
pub trait ComponentAny: Component + Any {
fn as_any(&self) -> &Any;
fn as_any_mut(&mut self) -> &mut Any;
}
impl<T> ComponentAny for T
where T: Component + Any
{
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
从这里开始,我只是将所有API更改为接受ComponentAny
而不是Component
。由于Any
是针对任何'static
类型自动实施的,因此ComponentAny
现在会自动为实现'static
的任何Component
类型实施。感谢Is there a way to combine multiple traits in order to define a new trait?的想法。