Why does Rust still consider the file to be of type `Result` even after I've handled the error in the main function?

Why does Rust still consider the file to be of type Result even after I've handled the error in the main function?

use std::{fs::File, io};

fn get_file(file_name: &str) -> Result<File, io::Error> {
    let file = File::open(file_name);

    let file_err = match file {
        Ok(file) => return Ok(file),
        Err(err) => err,
    };

    match file_err.kind() {
        io::ErrorKind::NotFound => File::create(file_name),
        _ => Err(file_err),
    }
}

fn main() {
    let file = get_file("random.txt");

    if let Err(err) = file {
        println!("Error: {}", err);
        return;
    }

    //                    Result<File, Error>
    println!("file {:?}", file);
}

You extracted the error from the Result and dealt with it, but you didn't extract the file from the Result. One way to do it is:

    let file = match file {
        Ok(f) = f,
        Err(err) => {
            println!("Error: {}", err);
            return;
        }
    };

    // now `file` is type File

Or perhaps this is better:

    let file = match get_file("random.txt") {
        Ok(f) = f,
        Err(err) => {
            println!("Error: {}", err);
            return;
        }
    };
5 Likes

It looks like you expect Rust to have flow-sensitive typing. It doesn't (and enum variants are not types – enums are sum types, not unions of types).

1 Like

Rust doesn't do type analysis like TypeScript or new instanceof in Java.

Type of a variable stays the same, even if you checked what is in it.

Result/Err is not special in Rust. It's just an enum, like enum R { A, B, C }, so if you checked that variable == R::A, it wouldn't change it to be R::B.

You need to pattern match on Result::Ok to get the non-error value, or use ? (Try) operator that does this match itself.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.