我有一个特性,我想提供一种方法.该方法将根据一些帮助者来实现,这些帮助者没有业务在特征内,并且非常简单,动态多态性比使它们通用更有意义.所以我有代码
fn use_trait(x: &Trait) {
println!("object says {}", x.needed());
}
trait Trait {
fn needed(&self) -> &str;
fn provided(&self) {
use_trait(self);
}
}
struct Struct();
impl Trait for Struct {
fn needed(&self) -> &str {
"Hello, world!"
}
}
fn main() {
Struct().provided();
}
Run Code Online (Sandbox Code Playgroud)
然而,哪个不能编译,错误:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> <anon>:9:19
|
9 | use_trait(self);
| ^^^^ the trait `std::marker::Sized` is not implemented for `Self`
|
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `Trait`
Run Code Online (Sandbox Code Playgroud)
我明白为什么,但不能保证别人不会实施的无胶型性状(从转换&T where T: Trait
到&Trait
需要T: Sized
的,但声明不要求).
但是,建议不会做我需要的.我可以补充一下
fn needed(&self) -> &str where Self: Sized
Run Code Online (Sandbox Code Playgroud)
但是然后该needed()
方法将无法在&Trait
(因为Trait : ?Sized
)上访问,这会使事物变得无用,因为类型(执行某些有用的实际的类型)总是被处理为Arc<Trait>
.并添加
trait Trait: Sized
Run Code Online (Sandbox Code Playgroud)
更糟糕,因为不允许&Trait
在所有(Trait
为一个类型为未分级的,所以Trait
类型并没有实现特质Trait
).
当然我可以简单地做
fn use_trait<T: Trait>(x: &T)
Run Code Online (Sandbox Code Playgroud)
但是在实际代码中有很多背后的东西,所以我不想在那里进行单态化,特别是因为特性总是作为特征对象处理.
有没有办法告诉Rust所有impl Trait
必须调整大小的类型,这里是一个应该适用于所有类型的方法的定义?
@JoshuaEntrekin 的答案的增强版:
\n辅助as_trait
函数可以放入一个辅助特征中,该特征可以为所有Sized
尝试实现的类型提供全面的实现Trait
。然后,实现者Trait
不需要做任何特殊的事情,转换就可以进行。
fn use_trait(x: &Trait) {\n println!("object says {}", x.needed());\n}\n\ntrait Trait : AsTrait {\n fn needed(&self) -> &str;\n\n fn provided(&self) where Self : AsTrait {\n use_trait(self.as_trait());\n }\n}\n\ntrait AsTrait {\n fn as_trait(&self) -> &Trait;\n}\n\nimpl<T : Trait + Sized> AsTrait for T {\n fn as_trait(&self) -> &Trait { self }\n}\n\nstruct Struct();\n\nimpl Trait for Struct {\n fn needed(&self) -> &str {\n "Hello, world!"\n }\n}\n\nfn main() {\n Struct().provided();\n}\n
Run Code Online (Sandbox Code Playgroud)\n(播放中)。
\n也可以简单地放入provided
辅助特征,但随后它必须动态地分派到其他Self
不必要的方法。
更新:实际上,重点是它仍然应该可以覆盖provided
.
现在可以通过使其通用来进一步改进上述内容。有std::makrer::Unsize,在撰写本文时它还不稳定。我们做不到
\ntrait Trait : Unsize<Trait>\n
Run Code Online (Sandbox Code Playgroud)\n因为 Rust 不允许CRTP,但幸运的是,对方法施加约束就足够了。所以
\nfn use_trait(x: &Trait) {\n println!("object says {}", x.needed());\n}\n\ntrait Trait {\n fn needed(&self) -> &str;\n\n fn provided(&self) where Self: AsObj<Trait> {\n use_trait(self.as_obj());\n }\n}\n\ntrait AsObj<Tr: ?Sized> {\n fn as_obj(&self) -> &Trait;\n}\n\n// For &\'a Type for Sized Type\nimpl<Type: Trait> AsObj<Trait> for Type {\n fn as_obj(&self) -> &Trait { self }\n}\n\n// For trait objects\nimpl AsObj<Trait> for Trait {\n fn as_obj(&self) -> &Trait { self }\n}\n\nstruct Struct();\n\nimpl Trait for Struct {\n fn needed(&self) -> &str {\n "Hello, world!"\n }\n \n fn provided(&self) {\n println!("Aber dieses Objekt sagt Gr\xc3\xbc\xc3\x9f Gott, Welt!"); // pardon my German, it is rusty.\n }\n}\n\nfn main() {\n let s: &Trait = &Struct();\n s.provided();\n}\n
Run Code Online (Sandbox Code Playgroud)\n(播放中)
\n这最终使得其他版本的实现者变得透明。
\n另请参阅此用户线程。
\n