Calling functions which return different types with shared trait and pass to other functions

匿名 (未验证) 提交于 2019-12-03 01:41:02

问题:

I'm still fairly new to rust. I would like to use a variable to choose between one of several functions which return structs of different types, but all of which have the same trait implemented. I would then like to pass the returned struct from the selected function to some functions which are meant to accept any variable which has that trait. However, I can't figure out how to do it. I've read How do I overcome match arms with incompatible types for structs implementing same trait? but I'm missing something because I still can't get it to work. The function which I pass the returned value to doesn't accept the value - see below.

Here's a simplified example using one of the methods from the above link:

trait IsEven {     fn is_even(&self) -> bool; }  struct First {     v: u8, }  impl IsEven for First {     fn is_even(&self) -> bool {         self.v % 2 == 0     } }  struct Second {     v: Vec<u8>, }  impl IsEven for Second {     fn is_even(&self) -> bool {         self.v[0] % 2 == 0     } }  fn make1() -> First {     First{v: 5} }  fn make2() -> Second {     Second{v: vec![2, 3, 5]} }   fn requires_is_even(v: impl IsEven) {     println!("{:?}", v.is_even()); }  fn main() {     for i in 0..2 {         let v1;         let v2;         let v = match i {             0 => {                 v1 = make1();                 &v1 as &IsEven             }             _ => {                 v2 = make2();                 &v2 as &IsEven             }         };         requires_is_even(v);  // This is where it fails     } }

The error I get in this case is:

52 |         requires_is_even(v);    |         ^^^^^^^^^^^^^^^^ the trait `IsEven` is not implemented for `&dyn IsEven`

I've also tried using Box as in some of the other examples in the link above, but still can't get it to work. Can anyone help?

Thanks

Bob

回答1:

requires_is_even, as you've written it, receives an object that implements IsEven by value, although all methods on the trait take self by shared reference. However, despite that, &dyn IsEven doesn't automatically implement IsEven (though we can add that implementation ourselves, see below).

You have a few options here:

  1. Change the function to receive an object implementing IsEven by shared reference. (This version does static dispatch.)

    fn requires_is_even(v: &(impl IsEven + ?Sized)) {      println!("{:?}", v.is_even()); }

    Note: The ?Sized bound is necessary here because impl Trait in argument position is syntactic sugar for a type parameter, and type parameters have an implicit Sized bound.

  2. Change the function to receive an IsEven trait object by shared reference. (This version does dynamic dispatch.)

    fn requires_is_even(v: &dyn IsEven) {     println!("{:?}", v.is_even()); }
  3. Implement IsEven for any shared reference to a type that implements IsEven.

    impl<T> IsEven for &T where     T: IsEven + ?Sized {     fn is_even(&self) -> bool {         (**self).is_even()     } }

    Note: By adding the ?Sized bound, this impl applies to &dyn IsEven as well. Trait objects (dyn IsEven here, not &dyn IsEven or Box<dyn IsEven>) automatically implement their corresponding trait (if the trait is object-safe, otherwise the trait object type isn't usable at all, by definition).



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!