Разработка модульных тестов, когда `Result` не является` Copy` - PullRequest
0 голосов
/ 21 января 2020

У меня есть модульный тест для типа контейнера, над которым я работаю:

#[test]
fn test_get_mut_normal_tail() -> Result<(), ListError> {
    let mut actual_list: ArrayList<u64> = ArrayList::new();
    let expected_list: ArrayList<u64> = ArrayList {
        elems: vec![1, 2, 3, 8],
    };

    actual_list.append(1)?;
    actual_list.append(2)?;
    actual_list.append(3)?;
    actual_list.append(4)?;

    let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
    let expected_res: Result<&mut u64, ListError> = Ok(&mut 4);

    let elem = actual_res.unwrap();
    *elem *= 2;

    assert_eq!(actual_list, expected_list);
    assert_eq!(actual_res, expected_res);

    Ok(())
}

Однако rustc жалуется на:

error[E0382]: borrow of moved value: `actual_res`
   --> src\arraylist.rs:358:9
    |
351 |         let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
    |             ---------- move occurs because `actual_res` has type `std::result::Result<&mut u64, list::ListError>`, which does not implement the `Copy` trait
...
354 |         let elem = actual_res.unwrap();
    |                    ---------- value moved here
...
358 |         assert_eq!(actual_res, expected_res);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Что я не делаю понять, потому что Result документы указывают, что Result реализует Copy (при условии, что оба содержащихся типа также). Ясно, что &mut u64 реализует Copy и мой ListError тип derive s, это также:

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ListError {
    OutOfBounds,
    Impossible,
}

Код для ArrayList::get_mut() здесь, если уместно:

fn get_mut(&mut self, pos: usize) -> Result<&mut T, ListError> {
    if pos >= self.elems.len() { /* bounds check */
        return Err(ListError::OutOfBounds);
    }

    match self.elems.get_mut(pos) {
        Some(elem) => Ok(elem),
        None => Err(ListError::OutOfBounds)
    }
}

В итоге у меня есть два вопроса:

  1. Как исправить эту ошибку?
  2. Существует ли основная проблема в моем тесте или моя реализация?

1 Ответ

1 голос
/ 21 января 2020

&mut u64 фактически не реализует копирование. &mut T не может реализовать копирование для предотвращения создания нескольких одновременных изменяемых заимствований.

Документация для справки: https://doc.rust-lang.org/std/primitive.reference.html#trait -имплементации

В ответ на 1 вы можете исправить ошибка при использовании assert_eq!(elem, 4); вместо assert_eq!(actual_res, expected_res);. Или вы можете использовать Result::map для изменения и возврата нового результата

let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3).map(|elem| {
  *elem *= 2;
  elem
};
...