Option 返回值
如果你调用的函数和你正在写的函数都返回 Option 类型,如果你调用的函数返回 None,你的函数也返回 None,这时,代码可以用问号 ? 操作符简化。看下面的例子:
fn foo() -> Option<i32> {
None
}
fn bar() -> Option<String> {
foo()?;
Some(String::from("Hello"))
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
None
Result 返回值
看个例子:
fn foo() -> Result<i32, String> {
Err(String::from("foo error!"))
}
fn bar() -> Result<String, String> {
foo()?;
Ok(String::from("Hello"))
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
Err("foo error!")
错误信息类型不一样,如何转换?
如果 foo
、bar
错误信息类型不一致,会有什么结果?看下面的例子:
fn foo() -> Result<i32, String> {
Err(String::from("foo error!"))
}
fn bar() -> Result<i32, i32> {
foo()?;
Ok(123)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
5 | foo()?;
| ^ the trait `From<String>` is not implemented for `i32`
一堆错误信息。仔细阅读其内容,错误信息说,如果为 i32
实现了 From<String>
特性,还是允许的。因此,只要 foo
的错误信息能够转换为 bar
函数的错误信息,还是允许的。这个简直太好了,因此,我决定用一个新的数据类型作为错误信息。再实验一下:
fn foo() -> Result<i32, String> {
Err(String::from("foo error!"))
}
#[derive(Debug)]
struct MyErr {
error_code: i32,
}
impl From<String> for MyErr {
fn from(s: String) -> Self {
if s.is_empty() {
MyErr { error_code: 0 }
} else {
MyErr { error_code: 1 }
}
}
}
fn bar() -> Result<i32, MyErr> {
foo()?;
Ok(123)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
Err(MyErr { error_code: 1 })
Option 转 Result
如果 foo
和 bar· 函数的返回类型分别是
Option 和
Result`,我们看会出现什么情况:
fn foo() -> Option<i32> {
None
}
#[derive(Debug)]
struct MyErr {
error_code: i32,
}
fn bar() -> Result<i32, MyErr> {
foo()?;
Ok(123)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
/ fn bar() -> Result<i32, MyErr> {
10 | | foo()?;
| | ^ use `.ok_or(...)?` to provide an error compatible with `Result<i32, MyErr>`
11 | | Ok(123)
12 | | }
| |_- this function returns a `Result`
编译期建议用 ok_or
方法进行转换。代码我们修改一下:
fn foo() -> Option<i32> {
None
}
fn bar() -> Result<i32, String> {
foo().ok_or("error".to_string())?;
Ok(123)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
Err("error")
ok_or
可以把 Option
类型转换为 Result,其实现代码如下:
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Some(v) => Ok(v),
None => Err(err),
}
}
类似的函数还有 ok_or_else
,允许用闭包实现更复杂的转换,此处不赘述。
Result 转 Option
继续试验:
fn foo() -> Result<i32,i32> {
Err(123)
}
fn bar() -> Option<i32> {
foo()?;
Some(0)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
4 | / fn bar() -> Option<i32> {
5 | | foo()?;
| | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
错误信息说,如果想提前丢弃计算结果,可以用 .ok()?
方法。代码修改一下:
fn foo() -> Result<i32,i32> {
Err(123)
}
fn bar() -> Option<i32> {
foo().ok()?;
Some(0)
}
fn main() {
println!("{:?}", bar());
}
========= cargo run =========
None
果然转换过来了。我们看看 ok()
的实现代码:
pub fn ok(self) -> Option<T> {
match self {
Ok(x) => Some(x),
Err(_) => None,
}
}
原来如此简单呀!