有没有办法使用Option :: and_then缩短非复制类型的匹配表达式?

Jmb*_*Jmb 9 rust

Option::and_then函数允许简化此代码:

let foo = Some(1);
let bar = match foo {
    Some(i) => Some(i + 1),
    None => None,
};
println!("Foo: {:?}", foo);
Run Code Online (Sandbox Code Playgroud)

进入这个:

let foo = Some(1);
let bar = foo.and_then(|i| Some(i + 1));
println!("Foo: {:?}", foo);
Run Code Online (Sandbox Code Playgroud)

如果我用Strings 尝试相同的东西,它不会编译:

let foo = Some("bla".to_string());
let bar = foo.and_then(|ref f| Some(f.clone()));
println!("Foo: {:?}", foo);
Run Code Online (Sandbox Code Playgroud)
error[E0382]: use of moved value: `foo`
 --> src/main.rs:4:27
  |
3 |     let bar = foo.and_then(|ref f| Some(f.clone()));
  |               --- value moved here
4 |     println!("Foo: {:?}", foo);
  |                           ^^^ value used here after move
  |
  = note: move occurs because `foo` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

但是,相应的match表达式有效:

let foo = Some("bla".to_string());
let bar = match foo {
    Some(ref f) => Some(f.clone()),
    None => None,
};
println!("Foo: {:?}", foo);
Run Code Online (Sandbox Code Playgroud)

有没有办法缩短这个匹配表达式,就像我的第一个带整数的例子一样?

操场上的代码

  • 在这个最小的例子中,我本来可以使用map,但在我的真实代码中,我正在调用另一个返回一个Option我真正需要的函数and_then.只是我不想用一个不影响问题的额外函数来复杂化这个例子.

  • 我真的需要foo事后使用,否则就不会有任何问题(实际上,foo我需要多次使用一个闭包捕获,而Man!我很难找到为什么编译器一直拒绝我的代码!错误the trait FnMut... is not implemented for the type [closure@...]没有给出很多指示,为什么它不是).

  • clone在示例中使用了因为我想要使用字符串进行简单的操作.在真正的代码中,foo不是一个字符串(它是一个Regex),我不是在闭包中克隆它(我将它应用于字符串并处理结果).此外,此代码将被多次调用,因此避免不必要的分配和复制很重要.

Luk*_*odt 13

说明

首先:您实际想要使用的方法是map在这里,因为您只想更改内部值.and_then如果Option在闭包中创建另一个,则非常有用.

回答你的问题:你不能再访问是正确的foo.如果你看一下函数声明......

fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U>
//                                        ^^^^
Run Code Online (Sandbox Code Playgroud)

......你看到第一个论点是self.这意味着该方法消耗self(获取所有权),因此foo被移入方法并且不能再使用.

如果您bar之后只需要(通常是这种情况),您应该打印bar.如果你真的需要foo,你也可以这样做:

let bar = foo.as_ref().map(|s| s.clone());
Run Code Online (Sandbox Code Playgroud)

as_ref创建一个Option只包含对原始内部变量的引用的new .引用是Copy类型,因此Option可以安全地使用map.


She*_*ter 5

你想使用Option::as_ref

fn main() {
    let foo = Some("bla".to_string());
    let bar = foo.as_ref().and_then(|f| Some(f.clone()));
    println!("Foo: {:?}", foo);
}
Run Code Online (Sandbox Code Playgroud)