【问题标题】:Testing iterator over dynamic trait objects在动态特征对象上测试迭代器
【发布时间】:2020-02-10 12:43:12
【问题描述】:

我有两种类型 AB 实现了 Fooable 特征。我有一个As 数组和一个Bs 数组,并在这两个数组上创建一个迭代器,该迭代器的项目类型为&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
        }
    );
}

问题在于 &amp;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?),无法为动态类型实现此特征。有什么办法可以达到这里的目标吗?我想可以改为在Fooable 特征中公开构成AB 类型对象的一些数据,并使用它来检查输出的对象是否正确(在我的实际用例中@987654337 @s 和 Bs 比我上面的玩具示例更复杂)。

【问题讨论】:

  • 看来How to get a reference to a concrete type from a trait object? 的答案可能会回答您的问题。如果没有,请edit您的问题来解释差异。否则,我们可以将此问题标记为已回答。
  • 在我的用例中,“create_vector”对象没有静态生命周期,我相信这意味着不能通过 Any?我已经相应地编辑了问题
  • 静态生命周期在一种安全、高效的内存管理语言中似乎没有吸引力——这似乎是不合理的。这两件事虽然相关,但在这种情况下彼此无关。

标签: rust


【解决方案1】:

在没有任何更好的想法的情况下,一种可能的解决方法是利用 As 和 Bs 的 Debug 特征:测试格式化的调试输出是否相等通常等同于预期的相等概念As 和 Bs。

/* ... */
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
    })
);

【讨论】:

    猜你喜欢
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 2018-11-04
    • 2016-08-27
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多