Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"the `and_then` method cannot be invoked on a trait object" error when type annotations are added to the `and_then`

Tags:

rust

I have a function passed to and_then that returns a type not known to the compiler. When chained with other option methods, type annotations are required.

fn main() {
    let w = Some("hi".to_string());
    let x: Option<&String> = w.as_ref();

    //fails:
    let y: Option<String> =
        x.and_then::<String, FnOnce(Option<&String>) -> Option<String>>(|_inner: &String| None);

    //ok:
    let y: Option<String> = x.and_then(|_inner: &String| None);
}

playground

Adding the mandatory annotations causes this compiler error:

error: the `and_then` method cannot be invoked on a trait object
 --> src/main.rs:7:11
  |
7 |         x.and_then::<String, FnOnce(Option<&String>) -> Option<String>>(|_inner: &String| None);
  |           ^^^^^^^^

I assume it is complaining about the FnOnce trait, but I don't see what this has to do with x.

I would like to understand what is going wrong here.

Ultimately, the goal is to have this and_then in a chained statement, which is why the annotations are needed.

let y = x
    .and_then::<String, FnOnce(Option<&String>) -> Option<String>>(|_inner: &String| None)
    .and(Some("new String".to_string()));
like image 969
marathon Avatar asked Dec 06 '18 22:12

marathon


1 Answers

There are multiple problems here:

  • Closures are an anonymous type, which means that you cannot name them.

  • It's currently impossible to have a bare trait like FnOnce because it is unsized.

  • || foo isn't a trait, it's a concrete type.

Instead, specify the return type of the closure:

let y = x
    .and_then(|_inner| -> Option<String> { None })
    .and(Some("new String".to_string()));

Or qualify the type of the None:

let y = x
    .and_then(|_inner| None::<String>)
    .and(Some("new String".to_string()));

Or avoid the chaining:

let y: Option<String> = x.and_then(|_inner| None);
let y = y.and(Some("new String".to_string()));
like image 71
Shepmaster Avatar answered Nov 06 '22 14:11

Shepmaster