3

The Rust file examples don't appear compile with Rust 1.18.0.

For example:

use std::fs::File;
use std::io::prelude::*;
fn main() {
    let mut file = File::open("foo.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    assert_eq!(contents, "Hello, world!");
}

Error log:

rustc 1.18.0 (03fc9d622 2017-06-06)
error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
 --> <anon>:4:20
  |
4 |     let mut file = File::open("foo.txt")?;
  |                    ----------------------
  |                    |
  |                    the trait `std::ops::Carrier` is not implemented for `()`
  |                    in this macro invocation
  |
  = note: required by `std::ops::Carrier::from_error`

error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
 --> <anon>:6:5
  |
6 |     file.read_to_string(&mut contents)?;
  |     -----------------------------------
  |     |
  |     the trait `std::ops::Carrier` is not implemented for `()`
  |     in this macro invocation
  |
  = note: required by `std::ops::Carrier::from_error`

error: aborting due to 2 previous errors
Stargateur
  • 20,831
  • 8
  • 51
  • 78
alexbirkett
  • 2,514
  • 2
  • 23
  • 29

2 Answers2

7

? is a syntactic sugar that checks a Result: if the result is Err, it is returned as if. If there is no error (aka Ok), the function continue. When you type this:

fn main() {
    use std::fs::File;

    let _ = File::open("foo.txt")?;
}

that means:

fn main() {
    use std::fs::File;

    let _ = match File::open("foo.txt") {
        Err(e)  => return Err(e),
        Ok(val) => val,
    };
}

Then you understand that for now, you cannot use ? in the main, because main returns unit () and not Result. If you want this stuff to work, you can put it in a function that returns a Result and check it from main:

fn my_stuff() -> std::io::Result<()> {
    use std::fs::File;
    use std::io::prelude::*;

    let mut file = File::open("foo.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    // do whatever you want with `contents`
    Ok(())
}


fn main() {
    if let Err(_) = my_stuff() {
        // manage your error
    }
}

PS: There is a proposition to make work ? in the main.

Boiethios
  • 31,388
  • 12
  • 113
  • 159
4

They do compile. They just don't compile in a main function like that. If you look at the examples, they all have a big "Run" button on them. Click that and it opens the full, unabridged example on the playpen.

The one you've used above expands to this code:

fn main() {
    use std::fs::File;
    use std::io::prelude::*;

    fn foo() -> std::io::Result<()> {
        let mut file = File::open("foo.txt")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        assert_eq!(contents, "Hello, world!");
        Ok(())
    }
}

That code doesn't compile because you've put code that propagates a Result into a function (main in this case) that doesn't return a Result.

Stargateur
  • 20,831
  • 8
  • 51
  • 78
DK.
  • 49,288
  • 3
  • 161
  • 146
  • I saw the run button and noted the code was different. My first thought was that one or other versions was out-of-date. I suspected also that it had something to do with the `?` but being brand new to rust I did not know what `?` did. – alexbirkett Jun 21 '17 at 08:53