Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I fix the error "type annotations needed" when creating a closure that uses the try operator?

use std::fs::File;

fn main() {
    let tmp = "tmp.zip";

    let save_to_tmp_file = || {
        let mut tmp_zip = File::create(tmp)?;
        Ok(())
    };

    save_to_tmp_file();
}

(playground)

The build error:

error[E0282]: type annotations needed
 --> src/main.rs:7:27
  |
6 |     let save_to_tmp_file = || {
  |         ---------------- consider giving `save_to_tmp_file` a type
7 |         let mut tmp_zip = File::create(tmp)?;
  |                           ^^^^^^^^^^^^^^^^^^ cannot infer type for `_`
like image 307
gary Avatar asked Jul 23 '18 10:07

gary


3 Answers

You have to specify the return type:

use std::fs::File;
use std::io;

fn main() {
    let tmp = "tmp.zip";

    let save_to_tmp_file = || -> Result<(), io::Error> {
        let mut tmp_zip = File::create(tmp)?;
        Ok(())
    };

    save_to_tmp_file();
}

There is a problem with the closure. You cannot name the type of a closure; you could try to reduce it to a FnOnce / FnMut, but you still would have to give it the return type.

To overcome your situation, you can specify a Result as a return type for your main function.

use std::io;
use std::fs::File;

fn main() -> Result<(), io::Error> {
    let tmp = "tmp.zip";
    let mut tmp_zip = File::create(tmp)?;
    Ok(())
}
like image 116
hellow Avatar answered Nov 16 '22 04:11

hellow


The compiler is unable to infer the return type of the closure.

Returning Ok(()) at the end lets the compiler infer what the type of a successful result is, but not what the error type would be. The return type of the ? operator does include the full concrete type but it's guarantee is that this type can be converted into whatever the the surrounding function returns. So we need to fix that return type so all of the elided type annotations can be inferred.

Tyfingr's answer fixes the problem by removing the ?, so that the return type of the closure is the same as the return type of File::create(tmp).

hellow's answer adds an annotation on the closure so that the compiler doesn't need to infer the type.

A third fix would be to put the type annotation on the return value:

let save_to_tmp_file = || {
    let mut tmp_zip = File::create(tmp)?;
    Ok(())
};

let result: Result<_, io::Error> = save_to_tmp_file();

Which is similar to hellow's edit, to put the type in the return value of main().

In general, you should use a Result, and the compiler will warn you if you don't. When you handle the error, you are very likely to inadvertently provide the compiler with enough type information that none of these annotations are necessary.

like image 3
Peter Hall Avatar answered Nov 16 '22 05:11

Peter Hall


Rust is an expressive language so you can just return the Result and it works fine:

use std::fs::File;

fn main() {
    let tmp = "tmp.zip";

    let save_to_tmp_file = || {
        File::create(tmp)
    };

    save_to_tmp_file().expect("Can't create a tmp file");
}

Or just write:

fn main() {
    let tmp = "tmp.zip";
    File::create(tmp).expect("Can't create a tmp file");
}
like image 1
Tyfingr Avatar answered Nov 16 '22 03:11

Tyfingr