【问题标题】:Can't compare `&Thing` with `Thing`无法将 `&Thing` 与 `Thing` 进行比较
【发布时间】:2018-10-05 00:35:26
【问题描述】:

我知道错误的含义,但我无法修复它。我正在使用mockers 来测试我的工作,并且在尝试验证提供给模拟特征函数的结构参数时遇到了困难。简化代码:

#[cfg(test)]
extern crate mockers;
#[cfg(test)]
extern crate mockers_derive;

#[cfg(test)]
use mockers_derive::mocked;

#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct Thing {
    pub key: String,
    pub class: String,
}

#[cfg_attr(test, mocked)]
pub trait DaoTrait {
    fn get(&self, thing: &Thing) -> String;
}

struct DataService {
    dao: Box<DaoTrait>,
}

impl DataService {
    pub fn get(&self, thing: &Thing) -> String {
        self.dao.get(thing)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use mockers::matchers::eq;
    use mockers::Scenario;

    #[test]
    fn my_test() {
        use mockers::matchers::check;
        let scenario = Scenario::new();
        let mut dao = scenario.create_mock_for::<DaoTrait>();
        let thing = Thing {
            key: "my test".to_string(),
            class: "for test".to_string(),
        };

        scenario.expect(
            dao.get_call(check(|t: &Thing| t.to_owned() == thing))
                .and_return("hello".to_string()),
        );
        let testee = DataService { dao: Box::new(dao) };

        let rtn = testee.get(&thing);
        assert_eq!(rtn, "hello");
    }
}

我得到了错误:

warning: unused import: `mockers::matchers::eq`
  --> src/main.rs:33:9
   |
33 |     use mockers::matchers::eq;
   |         ^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unused_imports)] on by default

error[E0277]: can't compare `&Thing` with `Thing`
  --> src/main.rs:47:57
   |
47 |             dao.get_call(check(|t: &Thing| t.to_owned() == thing))
   |                                                         ^^ no implementation for `&Thing == Thing`
   |
   = help: the trait `std::cmp::PartialEq<Thing>` is not implemented for `&Thing`

error[E0277]: the trait bound `mockers::matchers::BoolFnMatchArg<Thing, [closure@src/main.rs:47:32: 47:65 thing:_]>: mockers::MatchArg<&Thing>` is not satisfied
  --> src/main.rs:47:17
   |
47 |             dao.get_call(check(|t: &Thing| t.to_owned() == thing))
   |                 ^^^^^^^^ the trait `mockers::MatchArg<&Thing>` is not implemented for `mockers::matchers::BoolFnMatchArg<Thing, [closure@src/main.rs:47:32: 47:65 thing:_]>`
   |
   = help: the following implementations were found:
             <mockers::matchers::BoolFnMatchArg<T, F> as mockers::MatchArg<T>>

我查看了check的源代码:

pub fn check<T, F: Fn(&T) -> bool>(f: F) -> BoolFnMatchArg<T, F> {
    BoolFnMatchArg { func: f, _phantom: PhantomData }
}

我认为我给出的关闭|t: &amp;Thing| t.to_owned() == thing 是正确的。我也尝试了以下闭包,但都没有奏效。

|t: &Thing| t == &thing
|t: &Thing| *t == thing
|t: Thing| t == thing

Cargo.toml:

[dev-dependencies]
mockers = "0.12.1"
mockers_derive = "0.12.1"

【问题讨论】:

    标签: rust mocking


    【解决方案1】:

    您无法使用默认派生 PartialEqThing&amp;Thing 进行比较:

    #[derive(Debug, PartialEq)]
    struct Thing(String);
    
    fn main() {
        let t_val = Thing(String::new());
        let t_ref = &t_val;
    
        t_val == t_ref;
    }
    
    error[E0308]: mismatched types
     --> src/main.rs:8:14
      |
    8 |     t_val == t_ref;
      |              ^^^^^ expected struct `Thing`, found &Thing
      |
      = note: expected type `Thing`
                 found type `&Thing`
    

    要修复该错误,您需要执行以下两项操作之一:

    1. 匹配参考水平:

      • t_val == *t_ref

      • &amp;t_val == t_ref

    2. 对不匹配数量的引用实现相等:

      impl<'a> PartialEq<&'a Thing> for Thing {
          fn eq(&self, other: &&'a Thing) -> bool {
              self == *other
          }
      }
      
      impl<'a> PartialEq<Thing> for &'a Thing {
          fn eq(&self, other: &Thing) -> bool {
              *self == other
          }
      }
      

    但是,这些都不能解决您的实际问题。你误解了 mockers 库是如何工作的;您的闭包使用了错误的参考级别,它需要拥有要比较的值:

    let expected_thing = thing.clone();
    scenario.expect(
        dao.get_call(check(move |t: &&Thing| t == &&expected_thing))
            .and_return("hello".to_string()),
    );
    

    【讨论】:

    【解决方案2】:

    首先要注意的是t.to_owned() 生成&amp;Thing,而不是您可能预期的Thing。那是因为Thing 没有实现Clone,因此它也没有实现ToOwned(因为有一个全面的实现为所有Clone 类型实现ToOwned),它提供了to_owned方法。但是为什么通话仍然有效?因为引用实现了Clone,所以&amp;Thing 实现了ToOwned!这给了to_owned这个签名:

    fn to_owned(self: &&Thing) -> &Thing;
    

    您可以通过为Thing 派生Clone 来解决此问题。

    但是,您不需要克隆Thing 来比较它。您可以改为比较对 Thing 的两个引用(例如,通过编写 |t: &amp;Thing| t == &amp;thing)。 PartialEq::eq== 运算符转换为)通过引用获取参数,references implement PartialEq 通过剥离一层引用(即它们不比较指针值,与原始指针类型不同)。

    【讨论】:

    • 谢谢,我为Thing 派生了Clone,但是clousour `` 还不能工作。我得到错误:错误[E0277]:不满足特征绑定mockers::matchers::BoolFnMatchArg&lt;Thing, [closure@src\lib.rs:46:32: 46:65 thing:_]&gt;: mockers::MatchArg&lt;&amp;Thing&gt;
    • 我也试过|t: &amp;Thing| t == &amp;thing,在你回答之前没有派生Clone。它只是不起作用!
    • 不经测试就回答我感到羞耻!
    猜你喜欢
    • 1970-01-01
    • 2021-10-27
    • 2019-05-27
    • 2021-02-28
    • 2010-12-14
    • 1970-01-01
    • 2018-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多