Невозможно заимствовать как неизменяемый, поскольку он также заимствован как изменяемый при проверке вызова - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть функция, которая принимает замыкание для выполнения логики, связанной с выводом (например, отображение на стандартный вывод):

fn handle(mut output: impl FnMut(String) -> ()) -> Result<(), String> {
    // do something that produces output string `message`
    let message = "example".to_string();
    Ok(output(message))
}

Я пытаюсь написать интеграционный тест для этой функции, где я определяю функцию вывода заглушки, которая сохраняет строку вывода в локальную переменную:

#[test]
fn should_work() {
    let mut output_message = String::from("");
    let output = |message: String| {
        output_message = message;
    };

    let result = handle(output);

    assert!(result.is_ok());
    assert_eq!("blah", output_message);
}

Однако у меня есть ошибка:

error[E0502]: cannot borrow `output_message` as immutable because it is also borrowed as mutable
  --> src/lib.rs:18:24
   |
11 |     let output = |message: String| {
   |                  ----------------- mutable borrow occurs here
12 |         output_message = message;
   |         -------------- previous borrow occurs due to use of `output_message` in closure
...
18 |     assert_eq!("blah", output_message);
   |                        ^^^^^^^^^^^^^^ immutable borrow occurs here
19 | }
   | - mutable borrow ends here

Можно ли как-нибудь протестировать, используя этот подход? Я кратко искал несколько поддельных ящиков, но все ящики, кажется, не обновляются очень часто, и они все равно немного излишни для моего сценария.

Если нет, есть ли лучшая альтернатива для тестирования этой функции?

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Встроить замыкание:

#[test]
fn should_work() {
    let mut output_message = String::from("");

    let result = handle(|message| {
        output_message = message;
    });

    assert!(result.is_ok());
    assert_eq!("blah", output_message);
}

Таким образом, замыкание является временным и не заимствует значение в течение длительного времени.В качестве бонуса вы можете избежать спецификации типа в аргументе закрытия.

Или подождать несколько недель до Rust 1.31 и включить режим Rust 2018, который имеет нелексические времена жизни .

0 голосов
/ 14 ноября 2018

Вы можете поместить анонимную функцию в локальную область, так что она будет отброшена к тому времени, когда вы утверждаете:

#[test]
fn should_work() {
    let mut output_message = String::from("");

    let result = {
        let output = |message: String| {
            output_message = message;
        };

        handle(output)
    };

    assert!(result.is_ok());
    assert_eq!("blah", output_message);
}
...