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

时间:2015-11-18 12:02:50

标签: rust optional

在下面的示例程序中,有什么方法可以避免定义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)
}

对于那些也会说Haskell的人,我想这个问题也可以表达为“我们可以在Rust中使用任何工具代替liftM2吗?”

6 个答案:

答案 0 :(得分:15)

我不相信有一个等同于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))));
}

输出:

Some(15)

答案 1 :(得分:6)

从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,
    }
}

这可以与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))
}

答案 2 :(得分:5)

我不知道你是否可以归结为一行(编辑:哦,接受的答案很好地将其归结为一行),但你可以通过匹配元组来避免嵌套def myRound(x): r = x % 1 if r < 0.5: return x-r else: return x-r+1 :< / p>

match

答案 3 :(得分:4)

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

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)
}

这需要修改f,因此参数合并为单个tuple-argument。通过直接映射f,可以在不修改|args| f.call(args)的情况下进行,但您必须specify the closure kind of f

答案 4 :(得分:4)

您可以将immediately invoked function expression (IIFE)?(尝试)运算符结合使用:

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

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

    println!("{:?}", res);
}

将来,您可以使用 try块

#![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);
}

另请参阅:

答案 5 :(得分:0)

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

选项1

if let (Some(a), Some(b)) = (num_maybe, num_maybe2) {
    f(a, b)
}

选项2

num_maybe.and_then(|a| num_maybe2.map(|b| f(a, b))

选项3

[num_maybe, num_maybe2].into_iter().flatten().fold(0, f)