调用返回具有共享特征的不同类型并传递给其他函数的函数

时间:2019-01-31 22:17:28

标签: rust

我还是很陌生。我想使用一个变量在返回不同类型结构的几个函数之一中进行选择,但是所有这些函数都具有相同的特征。然后,我想将返回的结构从所选函数传递给某些函数,这些函数旨在接受具有该特征的任何变量。但是,我不知道如何去做。我已经读过How do I overcome match arms with incompatible types for structs implementing same trait?,但是由于我仍然无法正常工作,所以我错过了一些东西。我将返回值传递给的函数不接受该值-参见下文。

这是使用上面链接中的一种方法的简化示例:

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
    }
}

在这种情况下,我得到的错误是:

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

在上面链接的其他一些示例中,我也尝试使用Box,但是仍然无法正常使用。有人可以帮忙吗?

谢谢

鲍勃

1 个答案:

答案 0 :(得分:1)

如您所写,

requires_is_even会收到一个按值实现IsEven的对象,尽管该特征上的所有方法都通过共享引用获取self。但是,尽管如此,&dyn IsEven并不会自动实现IsEven(尽管我们可以自己添加该实现,请参见下文)。

您在这里有几个选择:

  1. 更改该函数,以通过共享引用接收实现IsEven的对象。 (此版本执行静态调度。)

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

    注意:这里的?Sized边界是必需的,因为参数位置的impl Trait是类型参数的语法糖,并且类型参数具有隐式的Sized绑定。

  2. 更改该函数以通过共享引用接收IsEven特征对象。 (此版本具有动态调度功能。)

    fn requires_is_even(v: &dyn IsEven) {
        println!("{:?}", v.is_even());
    }
    
  3. 对实现了IsEven的类型的任何共享引用都实施IsEven

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

    注意:通过添加约束?Sized,此impl也适用于&dyn IsEven。特质对象(此处为dyn IsEven,不是 &dyn IsEvenBox<dyn IsEven>)自动实现其对应的特征(如果特征为object-safe,则为特征对象类型完全不可用)。