提供方法cast和self to trait对象

Jan*_*dec 6 traits rust

我有一个特性,我想提供一种方法.该方法将根据一些帮助者来实现,这些帮助者没有业务在特征内,并且非常简单,动态多态性比使它们通用更有意义.所以我有代码

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必须调整大小的类型,这里是一个应该适用于所有类型的方法的定义?

Jan*_*dec 2

@JoshuaEntrekin 的答案的增强版:

\n

辅助as_trait函数可以放入一个辅助特征中,该特征可以为所有Sized尝试实现的类型提供全面的实现Trait。然后,实现者Trait不需要做任何特殊的事情,转换就可以进行。

\n
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不必要的方法。

\n
\n

更新:实际上,重点是它仍然应该可以覆盖provided.

\n

现在可以通过使其通用来进一步改进上述内容。有std::makrer::Unsize,在撰写本文时它还不稳定。我们做不到

\n
trait Trait : Unsize<Trait>\n
Run Code Online (Sandbox Code Playgroud)\n

因为 Rust 不允许CRTP,但幸运的是,对方法施加约束就足够了。所以

\n
fn 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