在动态特征对象上测试迭代器

时间:2019-10-13 20:18:53

标签: rust

我有两种实现A特征的BFooable类型。我有一个A和一个B的数组,并在两个数组上创建了一个迭代器,该迭代器的项目类型为&dyn Fooable。我想编写一个测试来确认迭代器输出正确的对象,例如:

struct C {
    as_array: [A; 2],
    bs_arry: [B; 2],
}

impl C {
    fn contents_iter(&self) -> FoosIterator {
        FoosIterator {
            a_iter: (&self.as_array).into_iter(),
            b_iter: (&self.bs_arry).into_iter(),
        }
    }
}

struct FoosIterator<'a> {
    a_iter: <&'a [A; 2] as IntoIterator>::IntoIter,
    b_iter: <&'a [B; 2] as IntoIterator>::IntoIter,
}

impl<'a> Iterator for FoosIterator<'a> {
    type Item = &'a dyn Fooable;
    fn next(&mut self) -> Option<Self::Item> {
        match self.a_iter.next() {
            Some(upper_slot) => Some(upper_slot),
            None => self.b_iter.next().map(|x| x as &dyn Fooable),
        }
    }
}

trait Fooable: std::fmt::Debug {
    fn calculate_num(&self) -> i32;
}

#[derive(PartialEq, Debug)]
struct A {
    value: i32,
}

impl Fooable for A {
    fn calculate_num(&self) -> i32 {
        self.value
    }
}

#[derive(PartialEq, Debug)]
struct B {
    value_1: i32,
    value_2: i32,
}

impl Fooable for B {
    fn calculate_num(&self) -> i32 {
        self.value_1 * 5 + self.value_2
    }
}

#[test]
fn test_contents_iter() {
    let c = C {
        as_array: [A { value: 3 }, A { value: 5 }],
        bs_arry: [
            B {
                value_1: 3,
                value_2: 1,
            },
            B {
                value_1: 5,
                value_2: 2,
            },
        ],
    };
    let mut iter = c.contents_iter();
    assert_eq!(
        *iter
            .next()
            .expect("Should have initial element from iterator"),
        A { value: 3 }
    );
    assert_eq!(
        *iter
            .next()
            .expect("Should have second element from iterator"),
        A { value: 5 }
    );
    assert_eq!(
        *iter
            .next()
            .expect("Should have third element from iterator"),
        B {
            value_1: 3,
            value_2: 1
        }
    );
    assert_eq!(
        *iter
            .next()
            .expect("Should have fourth element from iterator"),
        B {
            value_1: 5,
            value_2: 2
        }
    );
}

问题在于类型&dyn Fooable的对象没有实现PartialEq特征,因此无法进行相等性比较:

error[E0369]: binary operation `==` cannot be applied to type `dyn Fooable`
  --> src/lib.rs:73:5
   |
73 | /     assert_eq!(
74 | |         *iter
75 | |             .next()
76 | |             .expect("Should have initial element from iterator"),
77 | |         A { value: 3 }
78 | |     );
   | |      ^
   | |      |
   | |______dyn Fooable
   |        A
   |
   = note: an implementation of `std::cmp::PartialEq` might be missing for `dyn Fooable`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

据我了解(例如,来自How to test for equality between trait objects?的),无法为动态类型实现此特征。有什么办法可以达到目标呢?我想可以改为以A特征公开一些构成BFooable类型的对象的数据,并使用它来检查输出的对象是否正确(在我的实际使用案例AB比上面的我的玩具示例更复杂)。

1 个答案:

答案 0 :(得分:0)

在没有更好的主意的情况下,一种可能的解决方法是对AB使用Debug特性:测试格式化的调试输出是否相等通常等于预期的效果。 AB之间的平等概念。

/* ... */
assert_eq!(
    format!("{:?}", *iter
        .next()
        .expect("Should have initial element from iterator")),
    format("{:?}", A { value: 3 })
);
assert_eq!(
    format!("{:?}", *iter
        .next()
        .expect("Should have second element from iterator")),
    format("{:?}", A { value: 5 })
);
assert_eq!(
    format!("{:?}", *iter
        .next()
        .expect("Should have third element from iterator")),
    format("{:?}",         
    B {
        value_1: 3,
        value_2: 1
    })
);
assert_eq!(
    format!("{:?}", *iter
        .next()
        .expect("Should have third element from iterator")),
    format("{:?}",         
    B {
        value_1: 5,
        value_2: 2
    })
);