Каков рекомендуемый способ создания побочных эффектов в потоке управления с использованием Result?

Result::and_then() отлично подходит для составления потока управления.

fn some_fn() -> Result<String, Error> {
    Ok("Yay".to_string())
}
some_fn()
    .and_then(|value| some_other_fn())
    .and_then(|some_other_value| /* ... */)

Иногда мы хотим создать побочный эффект и по-прежнему распространять испускаемое значение. Допустим, мы хотим напечатать значение в момент его получения:

some_fn()
    .and_then(|value| {
        println!("{}", &value);
        some_other_fn()
    })
    .and_then(|some_other_value| /* ... */)

Есть лучший способ сделать это? Что-то вроде Оператор tap() реактивных расширений было бы здорово.

мы хотим напечатать значение в тот момент, когда мы его получим — но вы все равно хотите вызвать some_other_function? Если да, то что не так с тем, что у вас есть?
Shepmaster 07.04.2019 18:00

Это именно то, что я имею в виду. Ничего плохого в том, что у меня есть. Я просто держу глаза и уши открытыми для более элегантных решений (если это возможно). Ваш ответ, как всегда, имеет смысл - Спасибо!

Pascal Precht 07.04.2019 18:15

побочный эффект никогда не бывает элегантным

Stargateur 07.04.2019 18:40
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
3
435
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

map и and_then подходят, когда вы хотите преобразовать значение. Использование match или if let подходит для побочных эффектов:

let r = some_fn();

if let Ok(v) = &r {
    println!("{}", v);
}

r.and_then(|_| some_other_fn())

Смотрите также:

Предполагая, что вы заботитесь о побочных эффектах только тогда, когда Result есть Ok...

Вы также можете создать признак расширения, чтобы добавить нужный метод в Result. Я бы посоветовал назвать его inspect, так как это имя параллельный метод на Iterator.

trait InspectExt<T> {
    fn inspect<F>(self, f: F) -> Self
    where
        F: FnOnce(&T);
}

impl<T, E> InspectExt<T> for Result<T, E> {
    fn inspect<F>(self, f: F) -> Self
    where
        F: FnOnce(&T),
    {
        if let Ok(v) = &self {
            f(v)
        }
        self
    }
}
some_fn()
    .inspect(|v| println!("{}", v))
    .and_then(|_| some_fn())

Смотрите также:

Другие вопросы по теме