在下面的示例程序中,有什么方法可以避免必须定义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_then并Option::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)
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)
我不知道你是否可以归结为一行(编辑:哦,接受的答案很好地将其归结为一行),但你可以避免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)
let num_maybe = Some(5);
let num_maybe2 = Some(10);
let f = |a, b| {
a + b
};
Run Code Online (Sandbox Code Playgroud)
if let (Some(a), Some(b)) = (num_maybe, num_maybe2) {
f(a, b)
}
Run Code Online (Sandbox Code Playgroud)
num_maybe.and_then(|a| num_maybe2.map(|b| f(a, b))
Run Code Online (Sandbox Code Playgroud)
[num_maybe, num_maybe2].into_iter().flatten().fold(0, f)
Run Code Online (Sandbox Code Playgroud)
您可以使用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。
您可以将立即调用的函数表达式 (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)
也可以看看: