Option::and_then
功能允许简化此代码:
let foo = Some(1);
let bar = match foo {
Some(i) => Some(i + 1),
None => None,
};
println!("Foo: {:?}", foo);
进入这个:
let foo = Some(1);
let bar = foo.and_then(|i| Some(i + 1));
println!("Foo: {:?}", foo);
如果我对String
s尝试相同的操作,则无法编译:
let foo = Some("bla".to_string());
let bar = foo.and_then(|ref f| Some(f.clone()));
println!("Foo: {:?}", foo);
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
但是,相应的match
表达式有效:
let foo = Some("bla".to_string());
let bar = match foo {
Some(ref f) => Some(f.clone()),
None => None,
};
println!("Foo: {:?}", foo);
有没有办法缩短这个匹配表达式,就像我的第一个带整数的例子一样?
在这个最小的例子中,我可以使用map
,但在我的实际代码中,我正在调用另一个返回Option
的函数,所以我真的需要and_then
。只是我不想用一个不影响问题的额外功能使示例过于复杂。
之后我真的需要使用foo
,否则就不会有任何问题(实际上,foo
被我需要多次使用的闭包捕获,而Man !我是否很难找到编译器拒绝我的代码的原因!错误the trait FnMut... is not implemented for the type [closure@...]
没有说明为什么不能这样做。
我在示例中使用了clone
因为我想要使用字符串进行简单的操作。在实际代码中,foo
不是一个字符串(它是Regex
),我没有在闭包中克隆它(我将它应用于字符串并处理结果)。此外,此代码将被多次调用,因此避免不必要的分配和复制非常重要。
答案 0 :(得分:13)
首先:您实际想要使用的方法是map
,因为您只想更改内部值。如果您在闭包中创建另一个and_then
,则Option
非常有用。
回答您的问题:您无法再访问foo
,这是正确的。如果你看一下函数声明......
fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U>
// ^^^^
...你看到第一个参数是self
。这意味着该方法会消耗self
(获取所有权),因此foo
会被移入方法中,并且无法再使用。
如果您之后只需要bar
(通常就是这种情况),您应该只打印bar
。如果你真的需要foo
,你也可以这样做:
let bar = foo.as_ref().map(|s| s.clone());
as_ref
创建一个新的Option
,它只包含对原始内部变量的引用。引用为Copy
类型,因此Option
可以安全地使用map
。
答案 1 :(得分:4)
您想使用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);
}
答案 2 :(得分:0)
你可以克隆foo,并在结果上调用and_then
。
let bar = foo.clone().and_then (|f| Some (f));
答案 3 :(得分:0)
选项实现克隆,它可以按预期工作。
let foo = Some("bla".to_string());
let bar = foo.clone();