42533

Lifetime of Option::map's argument

I placee a string into an Option and try to map over it, e.g. to trim the string:

fn main() { let s = " i want to be trimmed ".to_string(); let s_opt = Some(s); let x = s_opt.map(|z| z.trim()); // let x = s_opt.map(|z| z.trim().to_string()); println!("'{:?}'", x); }

The compiler shows a lifetime error

error[E0597]: `z` does not live long enough
 --> src/main.rs:5:27
  |
5 |     let x = s_opt.map(|z| z.trim());
  |                           ^      - `z` dropped here while still borrowed
  |                           |
  |                           borrowed value does not live long enough
...
9 | }
  | - borrowed value needs to live until here


This is clear, since z is only defined in the closure and the argument is passed by value.

Since the original variable s lives for the entire block, shouldn't the compiler be able to figure out that z is actually s?

The only way I can get this to work is by adding to_string (see the commented line), but then I am creating a new string object.

Another solution I found is to make s_opt a type of Option<&String> (see the second code block), but since functions can't return this kind of type this is not really an option.

fn main() { let s = " i want to be trimmed ".to_string(); let s_opt = Some(&s); let x = s_opt.map(|z| z.trim()); println!("'{:?}'", x); }

Is there something I've overlooked or wouldn't it be better if the default implementation of map would be similar to this?

fn my_map<'r, F>(o: &'r Option<String>, f: F) -> Option<&'r str> where F: Fn(&'r String) -> &'r str, { match *o { None => None, Some(ref x) => Some(f(x)), } } fn main() { let s = " i want to be trimmed ".to_string(); let s_opt = Some(s); let x = my_map(&s_opt, |x| x.trim()); println!("'{:?}'", x); }

Answer1:

The map function consumes iterated values so they do not exist after the call to the given closure anymore. You cannot return references to them.

The best solution would be in-place trim on String directly. Sadly there is none in the standard library currently.

Your second solution is also possible with a small change. Instead of &String you take a &str:

fn main() { let s = "text".to_string(); let s_opt = Some(s.as_str()); let x = s_opt.map(|z| z.trim()); println!("{:?}", x); }

Answer2:

As noted, Option::map consumes the original value to produce the output value. This is the most flexible and efficient implementation as you can convert an Option<A> to an Option<B> without needing to clone the original value.

The solution in this case is to convert your Option<String> (really a &Option<String>) into an Option<&String> using Option::as_ref. Once you have an Option<&String>, you can consume it without losing ownership of the originalOption`:

fn main() { let s = Some(" i want to be trimmed ".to_string()); let x = s.as_ref().map(|z| z.trim()); println!("{:?}", x); }

Recommend

  • ListView ArrayAdapter filtering by two names
  • meteor client async pattern / how to implement a waitOn for a list of subscriptions w callbacks
  • Developing scraping script on docker image - how to overcome lack of visual browser?
  • InternalsVisibleTo is not working for wpf application
  • Deploy Test agent failing in VSTS due to WinRM issue
  • Application will not launch from command line full path, but will after CDing to directory
  • JS: innerHTML and DOM aren't cooperating
  • Ant: fileset “dir” attribute with a runtime expanded full path
  • Responsive left sidebar open close
  • Prevent page break in text block with iText, XMLWorker
  • C++ friend class std::vector
  • SyntaxError: (irb):26: both block arg and actual block given
  • quiver not drawing arrows just lots of blue, matlab
  • Who propagate bugfixes across branches (corporate development)?
  • Suppressing passwd when calling sqlplus from shell script
  • xcode don't localize specific strings
  • How to assign byte[] as a pointer in C#
  • Calling Worksheet functions from vba in foreign language versions of Excel
  • Assign variable to the value in HTML
  • Do I need to reset a Perl hash index?
  • Why Encoding.ASCII != ASCIIEncoding.Default in C#?
  • How to use carriage return with multiple line?
  • d3 v4 drag and drop with TypeScript
  • one Local Olampyad Questions on Informatic in 2011
  • Why does access(2) check for real and not effective UID?
  • ilmerge with a PFX file
  • Illegal mix of collations for operation for date/time comparison
  • C# - Is there a limit to the size of an httpWebRequest stream?
  • DirectX11 ClearRenderTargetViewback with transparent buffer?
  • javascript inside java/jsp code
  • Perl system calls when running as another user using sudo
  • vba code to select only visible cells in specific column except heading
  • Weird JavaScript statement, what does it mean?
  • How do you troubleshoot character encoding problems?
  • R: gsub and capture
  • How to format a variable of double type
  • KeystoneJS: Relationships in Admin UI not updating
  • Running Map reduces the dimensions of the matrices
  • How to Embed XSL into XML
  • Net Present Value in Excel for Grouped Recurring CF