Borrowing Option :: and_then

The Option::and_then function simplifies this code:

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

in it:

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

However, if I try to do the same with strings, it does not compile:

 let foo = Some ("bla".to_string()); let bar = foo.and_then (|ref f| Some (f.clone())); println! ("Foo: {:?}", foo); 

Gives error: use of moved value: 'foo' , because String not copied, which causes foo to move when and_then . 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 expression of correspondence, for example, my first example with integers?

Thanks.

Playground Code

Edit

In response to some of the comments:

  • In this minimal example, I could use map , but in my real code, I call another function that returns Option , so I really need and_then . I just did not want to unnecessarily complicate the example with an additional function that did not affect the problem.

  • I really need to use foo after this, otherwise there would be no problem (in fact, foo captured by the closure, which I need to use more than once, and Man! It's hard to keep track of why the compiler kept giving up my code! Error the trait FnMut... is not implemented for the type [ closure@... ] does not give much indication of why this is not so).

  • I used clone in this example because I need a simple operation using a string. In real code, foo not a string (this is a Regex ), and I do not clone it in a close (I apply it to the string and process the results). Moreover, this code will be called many times, so it is important to avoid unnecessary distributions and copies.

as_ref is what I wanted. I was looking for something similar in the docs, and I don't understand how I could have missed it. Thanks for the help!

+5
source share
4 answers

Explanation

First of all: the method you really want to use is map here, since you want to change only the internal value. and_then is useful if you create another Option in closure.

To answer your question: correct that you can no longer access foo . 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 ownership). Therefore, foo moved to the method and can no longer be used.

Decision:

If you only need bar (which is usually the case), you should simply type bar . If you really need foo , you can also do this:

 let bar = foo.as_ref().map(|s| s.clone()); 

as_ref creates a new Option that contains only a reference to the original internal variable. Links are Copy types, so Option can use map safely.

+8
source

You want to use 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); } 

As a side note, in function calls like Some() or macrocells like println! There is no place before parens.

+4
source

You can just clone foo and call and_then for the result.

 let bar = foo.clone().and_then (|f| Some (f)); 
0
source

The option implements a clone that works as you expected.

 let foo = Some("bla".to_string()); let bar = foo.clone(); 
0
source

Source: https://habr.com/ru/post/1233177/


All Articles