The Option::and_then
function allows simplifying this code:
let foo = Some(1);
let bar = match foo {
Some(i) => Some(i + 1),
None => None,
};
println!("Foo: {:?}", foo);
into this:
let foo = Some(1);
let bar = foo.and_then(|i| Some(i + 1));
println!("Foo: {:?}", foo);
If I try the same thing with String
s, it doesn't compile:
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
However, the corresponding match
expression works:
let foo = Some("bla".to_string());
let bar = match foo {
Some(ref f) => Some(f.clone()),
None => None,
};
println!("Foo: {:?}", foo);
Is there a way to shorten this match expression like my first example with integers?
Code on playground
In this minimal example, I could have used map
, but in my real code I'm calling another function that returns an Option
so I really need and_then
. It's just that I didn't want to over-complicate the example with an extra function that didn't affect the problem.
I really need to use foo
afterwards, otherwise there wouldn't be any problem (actually, foo
is captured by a closure that I need to use more than once, and Man! did I have a hard time tracking down why the compiler kept refusing my code! The error the trait FnMut... is not implemented for the type [closure@...]
doesn't give much indication into why it isn't).
I used clone
in the example because I wanted a simple operation using the string. In the real code, foo
is not a string (it's a Regex
) and I'm not cloning it in the closure (I'm applying it on a string and processing the results). Moreover, this code will be called a large number of times so avoiding unnecessary allocations and copies is important.
That thing–the Paste Options button –is your friend, a worker bee and not a fly whose only job is to follow your formatting instructions. Learning how it works keeps you from wasting time manually formatting pasted text.
The hyphens within the regex are entered as literal characters and will be matched as such. After crafting our regex pattern, we’ll store that pattern into a variable called phoneNumRegex. We’ll then store phoneNumRegex into mo which is a special variable that returns the matched object.
You can see that we’re repeating \d three and four times in sequence which will actually match the same pattern a North American phone number follows. The hyphens within the regex are entered as literal characters and will be matched as such. After crafting our regex pattern, we’ll store that pattern into a variable called phoneNumRegex.
First of all: The method you actually want to use is map
here, since you only want to change the inner value. and_then
is useful if you create another Option
in the closure.
To answer your question: It's correct that you can't access foo
anymore. If you look at the function declaration...
fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U>
// ^^^^
... you see that the first argument is self
. This means that the method consumes self
(acquires the ownership) so foo
is moved into the method and can't be used anymore.
If you only need bar
afterwards (which is usually the case), you should just print bar
. If you really need foo
, too, you can do this:
let bar = foo.as_ref().map(|s| s.clone());
as_ref
creates a new Option
that only holds a reference to the original inner variable. References are Copy
types, so that Option
can be safely consumed by map
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With