2

The second map statement in this code fails to compile.

fn main() {
    let hello = Some("hello");
    let _switcheroo = hello.map(str::to_string); //ok

    let hello = Some("hello".to_string());
    let _switcheroo = hello.map(String::as_str); //not ok
}

The error is:

error[E0631]: type mismatch in function arguments
 --> src/main.rs:6:29
  |
6 |     let _switcheroo = hello.map(String::as_str); //not ok
  |                             ^^^
  |                             |
  |                             expected signature of `fn(std::string::String) -> _`
  |                             found signature of `for<'r> fn(&'r std::string::String) -> _`

I would expect an error about borrowing some moved data. What is this error trying to say?

This does compile:

let hello = Some("hello".to_string());
let _switcheroo = hello.as_ref().map(String::as_str); //ok
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
marathon
  • 7,881
  • 17
  • 74
  • 137

1 Answers1

2

The problem is that String::as_str expects a reference to a String rather than the String itself. String::as_str's signature is fn as_str(&self) -> &str, so you can see that it takes self (the String) as a reference.

To interpret the error message, look at the "expected" vs "found". In the "expected" part of the message, we see fn(std::string::String) -> _, so it's expecting a function that takes std::string::String (i.e. String) and returns some irrelevant type (_). In the "found" part of the message however, we find for<'r> fn(&'r std::string::String) -> _. This is harder to understand since it uses an idea that's rarely seen in Rust code.

The for<'r> part means that the function should be generic with respect to the lifetime. It should accept any lifetime and a String with that lifetime. The output type can also have the given lifetime. Usually a function like this has a signature like fn foo(x: &T) -> &U and the lifetimes are implicitly added. This is exactly what String::as_str is.

One way to fix your code is to ensure that a reference is passed to map. Something like let _switcheroo = hello.as_ref().map(String::as_str); should work.

SCappella
  • 9,534
  • 1
  • 26
  • 35