Невозможно сравнить `& Thing` с` Thing` - PullRequest
0 голосов
/ 05 октября 2018

Я знаю, что означает ошибка, но не могу ее исправить.Я использую 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: &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"

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Вы не можете сравнить Thing с &Thing, используя производное по умолчанию PartialEq:

#[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

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

Однако ни одно из этих действий не решает ваша актуальная проблема .Вы неправильно поняли, как работает библиотека издателей;ваше закрытие использует неверный уровень отсчета, и оно должно стать владельцем значения, чтобы сравнить:

let expected_thing = thing.clone();
scenario.expect(
    dao.get_call(check(move |t: &&Thing| t == &&expected_thing))
        .and_return("hello".to_string()),
);
0 голосов
/ 05 октября 2018

Первое, что нужно заметить (каламбур), это то, что t.to_owned() производит &Thing, а не Thing, как вы могли ожидать.Это потому, что Thing не реализует Clone, и, следовательно, он также не реализует ToOwned (потому что есть общий имплик, который реализует ToOwned для всех типов Clone),который обеспечивает метод to_owned.Но тогда почему звонок все еще работает?Поскольку ссылки реализуют Clone, то &Thing реализует ToOwned!Это дает to_owned эту подпись:

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

Вы можете исправить это, получив Clone для Thing.

Однако вам не нужно , нужно клонировать Thing, чтобы сравнить его.Вместо этого вы можете сравнить две ссылки с Thing (например, написав |t: &Thing| t == &thing).PartialEq::eq (который переводит оператор ==) принимает свои аргументы по ссылке, а ссылки реализуют PartialEq путем отделения слоя ссылок (т.е. они несравнить значения указателя, в отличие от необработанных типов указателей).

...