有没有内置的方法来"组合"两个选项?

Eri*_*aas 15 optional rust

在下面的示例程序中,有什么方法可以避免必须定义map2吗?

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a {
        Some(x) => match b {
            Some(y) => Some(f(x, y)),
            None => None,
        },
        None => None,
    }
}

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };
    let res = map2(f, a, b);
    println!("{:?}", res);
    // prints Some(15)
}
Run Code Online (Sandbox Code Playgroud)

对于那些也讲Haskell的人来说,我想这个问题也可以被称为"我们可以使用任何工具而不是Rust中的liftM2吗?"

Dog*_*ert 17

我不相信有一个直接的功能liftM2,但你可以结合Option::and_thenOption::map喜欢这样:

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| {
        a + b
    };

    println!("{:?}", a.and_then(|a| b.map(|b| f(a, b))));
}
Run Code Online (Sandbox Code Playgroud)

输出:

Some(15)
Run Code Online (Sandbox Code Playgroud)

  • 另一个选项有点长,但可能更容易理解:`a.and_then(|a| b.and_then(|b| Some(f(a, b))))` (2认同)

She*_*ter 10

从 Rust 1.46.0 开始,您可以使用Option::zip

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    match a.zip(b) {
        Some((x, y)) => Some(f(x, y)),
        None => None,
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以与 结合Option::map,如其他答案所示:

fn map2<T, U, V, F: Fn(T, U) -> V>(f: F, a: Option<T>, b: Option<U>) -> Option<V> {
    a.zip(b).map(|(x, y)| f(x, y))
}
Run Code Online (Sandbox Code Playgroud)


Jac*_*nor 7

我不知道你是否可以归结为一行(编辑:哦,接受的答案很好地将其归结为一行),但你可以避免match通过匹配元组来嵌套:

let a = Some(5);
let b = Some(10);
let f = |a, b| {
    a + b
};
let res = match (a, b) {
    (Some(a), Some(b)) => Some(f(a, b)),
    _ => None,
};
println!("{:?}", res);
// prints Some(15)
Run Code Online (Sandbox Code Playgroud)

  • 我不确定它应该.请注意,如果***参数为"None",原始问题中的示例和上面的`and_then` +`map`示例都会返回`None`.通常,如果`f`的返回类型与其参数的类型不同,则可能无法返回除"None"以外的任何内容.也就是说,如果你想要这种情况下的后备,你可以用`_ => a.or(b)`替换`_ => None`子句. (3认同)

Ben*_*Ben 7

let num_maybe = Some(5);
let num_maybe2 = Some(10);
let f = |a, b| {
    a + b
};
Run Code Online (Sandbox Code Playgroud)

选项1

if let (Some(a), Some(b)) = (num_maybe, num_maybe2) {
    f(a, b)
}
Run Code Online (Sandbox Code Playgroud)

选项2

num_maybe.and_then(|a| num_maybe2.map(|b| f(a, b))
Run Code Online (Sandbox Code Playgroud)

选项3

[num_maybe, num_maybe2].into_iter().flatten().fold(0, f)
Run Code Online (Sandbox Code Playgroud)


oli*_*obk 5

您可以使用Options 可以迭代的事实。迭代这两个选项,将它们压缩在一起,然后将生成的迭代器映射到您的函数上。

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |(a, b)| {
        a + b
    };
    let res = a.iter().zip(b.iter()).map(f).next();
    println!("{:?}", res);
    // prints Some(15)
}
Run Code Online (Sandbox Code Playgroud)

这需要修改f,因此参数被合并为一个元组参数。无需修改f,直接映射 over是可能的|args| f.call(args),但是您必须指定闭包类型f


She*_*ter 5

您可以将立即调用的函数表达式 (IIFE)?(try) 运算符结合使用:

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| a + b;

    let res = (|| Some(f(a?, b?)))();

    println!("{:?}", res);
}
Run Code Online (Sandbox Code Playgroud)

将来,您可以使用try blocks

#![feature(try_blocks)]

fn main() {
    let a = Some(5);
    let b = Some(10);
    let f = |a, b| a + b;

    let res: Option<_> = try { f(a?, b?) };

    println!("{:?}", res);
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: