是否有一种简单的方法来链接 return 选项值的函数的结果?
Is there a non-messy way to chain the results of functions that return Option values?
我有一些代码如下所示:
f(a).and_then(|b| {
g(b).and_then(|c| {
h(c).map(|d| {
do_something_with(a, b, c, d)
})
})
})
其中 f
、g
和 h
return Option
值。我需要在 do_something_with
计算中使用所有中间值(a
、b
、c
和 d
)。压痕很深。有一个更好的方法吗?理想情况下它看起来像这样(当然行不通):
try {
let b = f(a);
let c = g(b);
let d = h(c);
do_something_with(a, b, c, d)
} rescue NonexistentValueException {
None
}
Rust 1.22
现在支持Option
,所以你可以把你的函数写成
fn do_something(a: i32) -> Option<i32> {
let b = f(a)?;
let c = g(b)?;
let d = h(c)?;
do_something_with(a, b, c, d) // wrap in Some(...) if this doesn't return an Option
}
生锈 1.0
Rust 标准库定义了一个 try!
宏(以及等效的 ?
运算符,从 Rust 1.13 开始)解决了 Result
的这个问题。宏看起来像这样:
macro_rules! try {
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
$crate::result::Result::Err(err) => {
return $crate::result::Result::Err($crate::convert::From::from(err))
}
})
}
如果参数是 Err
,它 returns 来自具有 Err
值的函数。否则,它的计算结果为 Ok
中包含的值。该宏只能用于returns Result
的函数中,因为它returns 它遇到的错误。
我们可以为Option
做一个类似的宏:
macro_rules! try_opt {
($expr:expr) => (match $expr {
::std::option::Option::Some(val) => val,
::std::option::Option::None => return None
})
}
然后您可以像这样使用这个宏:
fn do_something(a: i32) -> Option<i32> {
let b = try_opt!(f(a));
let c = try_opt!(g(b));
let d = try_opt!(h(c));
do_something_with(a, b, c, d) // wrap in Some(...) if this doesn't return an Option
}
受 Result 的 try!
概念的启发,如果 monad 下降到 None.
,让我们将我们自己的宏从范围包装到 early-return
macro_rules! get(
($e:expr) => (match $e { Some(e) => e, None => return None })
);
(盗自 this reddit thread)
现在您可以运行您的代码线性化了:
fn blah() -> Option<...> { // ... is the return type of do_something_with()
let a = 123;
let b = get!(f(a));
let c = get!(g(b));
let d = get!(h(c));
do_something_with(a, b, c, d)
}
我有一些代码如下所示:
f(a).and_then(|b| {
g(b).and_then(|c| {
h(c).map(|d| {
do_something_with(a, b, c, d)
})
})
})
其中 f
、g
和 h
return Option
值。我需要在 do_something_with
计算中使用所有中间值(a
、b
、c
和 d
)。压痕很深。有一个更好的方法吗?理想情况下它看起来像这样(当然行不通):
try {
let b = f(a);
let c = g(b);
let d = h(c);
do_something_with(a, b, c, d)
} rescue NonexistentValueException {
None
}
Rust 1.22
Option
,所以你可以把你的函数写成
fn do_something(a: i32) -> Option<i32> {
let b = f(a)?;
let c = g(b)?;
let d = h(c)?;
do_something_with(a, b, c, d) // wrap in Some(...) if this doesn't return an Option
}
生锈 1.0
Rust 标准库定义了一个 try!
宏(以及等效的 ?
运算符,从 Rust 1.13 开始)解决了 Result
的这个问题。宏看起来像这样:
macro_rules! try {
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
$crate::result::Result::Err(err) => {
return $crate::result::Result::Err($crate::convert::From::from(err))
}
})
}
如果参数是 Err
,它 returns 来自具有 Err
值的函数。否则,它的计算结果为 Ok
中包含的值。该宏只能用于returns Result
的函数中,因为它returns 它遇到的错误。
我们可以为Option
做一个类似的宏:
macro_rules! try_opt {
($expr:expr) => (match $expr {
::std::option::Option::Some(val) => val,
::std::option::Option::None => return None
})
}
然后您可以像这样使用这个宏:
fn do_something(a: i32) -> Option<i32> {
let b = try_opt!(f(a));
let c = try_opt!(g(b));
let d = try_opt!(h(c));
do_something_with(a, b, c, d) // wrap in Some(...) if this doesn't return an Option
}
受 Result 的 try!
概念的启发,如果 monad 下降到 None.
macro_rules! get(
($e:expr) => (match $e { Some(e) => e, None => return None })
);
(盗自 this reddit thread)
现在您可以运行您的代码线性化了:
fn blah() -> Option<...> { // ... is the return type of do_something_with()
let a = 123;
let b = get!(f(a));
let c = get!(g(b));
let d = get!(h(c));
do_something_with(a, b, c, d)
}