Correct usage of std::File::open and std::File::read

I'm attempting to open a file and read the bytes of that file into a slice that's a member of a struct.

use std::fs::File;
struct Chip8 {
    op_code: u16,
    pub memory: [u8; MEM_LIMIT],
    cpu_register: [u8; DATA_REGISTERS],
    address_register: u16,
    program_counter: usize,
    stack: [u8; STACK_SIZE],
    gfx: [u8; SCREEN_WIDTH * SCREEN_HEIGHT],
    delay_timer: u8,
    sound_timer: u8,
    key: [u8; KEYPAD_KEYS],
    draw_flag: bool,
}

impl Chip8 {
    pub fn load_game(&mut self, name: &String) -> () {
        let mut f = File::open(name)?;
        let mut buffer = &mut self.memory[512..];

        f.read(&mut buffer)?;
    }
}

When I try to build this, I receive the following errors:

error[E0277]: the ? operator can only be used in a function that returns Result or Option (or another type that implements std::ops::Try)
--> src\main.rs:111:21
|
111 | let mut f = File::open("foot.txt")?;
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot use the ? operator in a function that returns ()
|
= help: the trait std::ops::Try is not implemented for ()
= note: required by std::ops::Try::from_error

error[E0277]: the ? operator can only be used in a function that returns Result or Option (or another type that implements std::ops::Try)
--> src\main.rs:114:9
|
114 | f.read(&mut buffer)?;
| ^^^^^^^^^^^^^^^^^^^^ cannot use the ? operator in a function that returns ()
|
= help: the trait std::ops::Try is not implemented for ()
= note: required by std::ops::Try::from_error

When I look at the documentation for std::fs::FIle::open, I see that it returns a Result type, but the compiler seems to telling me that std::fs::File::open returns a void type ().

Am I approaching this wrong? Thank you!

The error is saying that you cannot use ? operator in a function that returns (). That makes sense, since the whole purpose of this operator is to return error from the current function, so the function must be prepared for this. Change your load_game function, so that it return io::Result<()>, and all should work.

3 Likes

Additionally to the issues mentioned by @Cerberuser notice that you are using &mut twice on the buffer: First when writing &mut self.memory[512..] and again when writing &mut buffer. You just want one mutable reference.

Additionally you probably want to read the documentation on read, because this function does not guarantee that it will fill up the entire buffer you give it. It returns an usize, which contains the number of bytes it read, and to make sure the full buffer is filled, you must use a loop. Fortunately Rust provides a read_exact method, which internally contains the loop I mentioned, and it will always fill the buffer completely or fail with an error.

1 Like

Thanks for the additional feedback!