How to match a file extension represented as an Os

2019-06-27 04:20发布

问题:

I am trying to match against a file extension:

let file_path = std::path::Path::new("index.html");
let content_type = match file_path.extension() {
    None => "",
    Some(os_str) => match os_str {
        "html" => "text/html",
        "css" => "text/css",
        "js" => "application/javascript",
    },
};

The compiler says:

error[E0308]: mismatched types
 --> src/main.rs:6:13
  |
6 |             "html" => "text/html",
  |             ^^^^^^ expected struct `std::ffi::OsStr`, found str
  |
  = note: expected type `&std::ffi::OsStr`
             found type `&'static str`

回答1:

OsStr and OsString exist precisely because filenames are not UTF-8. A Rust string literal is UTF-8. That means you must deal with converting between the two representations.

One solution is to give up the match and use if-else statements. See Stargateur's answer for an example.

You can also convert the extension to a string. Since the extension might not be UTF-8, this returns another Option:

fn main() {
    let file_path = std::path::Path::new("index.html");
    let content_type = match file_path.extension() {
        None => "",
        Some(os_str) => {
            match os_str.to_str() {
                Some("html") => "text/html",
                Some("css") => "text/css",
                Some("js") => "application/javascript",
                _ => panic!("You forgot to specify this case!"),
            }
        }
    };
}

If you want all cases to use an empty string as the fallback, you can do something like:

use std::ffi::OsStr;

fn main() {
    let file_path = std::path::Path::new("index.html");
    let content_type = match file_path.extension().and_then(OsStr::to_str) {
        Some("html") => "text/html",
        Some("css") => "text/css",
        Some("js") => "application/javascript",
        _ => "",
    };
}

Or if you want to use None as the fallback:

use std::ffi::OsStr;

fn main() {
    let file_path = std::path::Path::new("index.html");

    let content_type = file_path.extension().and_then(OsStr::to_str).and_then(|ext| {
        match ext {
            "html" => Some("text/html"),
            "css" => Some("text/css"),
            "js" => Some("application/javascript"),
            _ => None,
        }
    });
}


回答2:

You could use PartialEq<str> trait for OsStr.

fn main() {
    let file_path = std::path::Path::new("index.html");
    let content_type = match file_path.extension() {
        None => "",
        Some(os_str) => {
            if os_str == "html" {
                "text/html"
            } else if os_str == "css" {
                "text/css"
            } else if os_str == "js" {
                "application/javascript"
            } else {
                ""
            }
        }
    };
    println!("{:?}", content_type);
}


标签: string rust