在Rust中使用具有特征的Any

时间:2017-02-05 19:41:12

标签: rust traits

我正在尝试在Rust中为具有子类型的特征实现PartialEq,以便我可以将它们添加为容器的盒装指针,然后进行比较。

这是我的缩小实施:

use std::any::Any;

trait Foo: Any {}

struct Bar {}

impl Foo for Bar {}

struct Baz {}

impl Foo for Baz {}

impl PartialEq for Foo {
    fn eq(&self, other: &Foo) -> bool {
        let me = self as &Any;
        let you = other as &Any;
        if me.is::<Bar>() && you.is::<Bar>() {
            true
        } else if me.is::<Baz>() && you.is::<Baz>() {
            true
        } else {
            false
        }
    }
}

fn main() {
    let bar: Bar = Bar {};
    let baz: Baz = Baz {};
    let foo1: &Foo = &bar;
    let foo2: &Foo = &baz;
    println!("{:?}", foo1 == foo2);
}

Code example in Rust Playground

当我建立这个时,我得到:

rustc 1.17.0-nightly (0648517fa 2017-02-03)
error: non-scalar cast: `&Foo + 'static` as `&std::any::Any + 'static`
  --> <anon>:15:18
   |
15 |         let me = self as &Any;
   |                  ^^^^^^^^^^^^

error: non-scalar cast: `&Foo + 'static` as `&std::any::Any + 'static`
  --> <anon>:16:19
   |
16 |         let you = other as &Any;
   |                   ^^^^^^^^^^^^^

error: aborting due to 2 previous errors

令人困惑。我在这里做错了什么想法?

修改:我不认为这是Why doesn't Rust support trait object upcasting?的副本,因为我要做的是使用Any进行向下转换,而不是向上转发。

进一步编辑:是的,这是重复的 - 对不起,我正在考虑我要做的事情(向下转换为BarBaz类型)而不是我这样做(向上转移到Any)。然而,话虽如此,我想我仍然不明白为什么Any example,他们这样做:let value_any = value as &Any;有效,而我的不行。话虽如此,Joshua Entrekin确实给出了一个很好的答案。

最终编辑一个,没关系,这是因为我正在向上倾斜一个特征而不是一个类型 - Doh!。谢谢大家!

1 个答案:

答案 0 :(得分:7)

这是Why doesn't Rust support trait object upcasting?的副本,因为您正尝试从Foo转播到Any。如果您向as_any添加Foo方法并对其进行实施,则可以使此代码生效:

use std::any::Any;

trait Foo: Any {
    fn as_any(&self) -> &Any;
}

impl<T: Any> Foo for T {
    fn as_any(&self) -> &Any {
        self
    }
}

struct Bar {}

struct Baz {}

impl PartialEq for Foo {
    fn eq(&self, other: &Foo) -> bool {
        let me = self.as_any();
        let you = other.as_any();
        if me.is::<Bar>() && you.is::<Bar>() {
            true
        } else if me.is::<Baz>() && you.is::<Baz>() {
            true
        } else {
            false
        }
    }
}

fn main() {
    let bar: Bar = Bar {};
    let baz: Baz = Baz {};
    let foo1: &Foo = &bar;
    let foo2: &Foo = &baz;
    println!("{:?}", foo1 == foo2);
}

我在Playground显示它。