简体   繁体   English

用于从Rust中的给定路径中提取文件扩展名

[英]Extracting a file extension from a given path in Rust idiomatically

I am trying to extract the extension of a file from a given String path. 我试图从给定的String路径中提取文件的扩展名。

The following piece of code works, but I was wondering if there is a cleaner and more idiomatic Rust way to achieve this: 下面这段代码可以工作,但我想知道是否有一个更干净,更惯用的Rust方法来实现这个目的:

use std::path::Path;

fn main() {

    fn get_extension_from_filename(filename: String) -> String {

        //Change it to a canonical file path.
        let path = Path::new(&filename).canonicalize().expect(
            "Expecting an existing filename",
        );

        let filepath = path.to_str();
        let name = filepath.unwrap().split('/');
        let names: Vec<&str> = name.collect();
        let extension = names.last().expect("File extension can not be read.");
        let extens: Vec<&str> = extension.split(".").collect();

        extens[1..(extens.len())].join(".").to_string()
    }

    assert_eq!(get_extension_from_filename("abc.tar.gz".to_string()) ,"tar.gz" );
    assert_eq!(get_extension_from_filename("abc..gz".to_string()) ,".gz" );
    assert_eq!(get_extension_from_filename("abc.gz".to_string()) , "gz");

}

In idiomatic Rust the return type of a function that can fail should be an Option or a Result . 在惯用Rust中,可能失败的函数的返回类型应该是OptionResult In general, functions should also accept slices instead of String s and only create a new String where necessary. 通常,函数也应该接受切片而不是String并且只在必要时创建一个新的String This reduces excessive copying and heap allocations. 这减少了过多的复制和堆分配。

You can use the provided extension() method and then convert the resulting OsStr to a &str : 您可以使用提供的extension()方法,然后将生成的OsStr转换为&str

use std::path::Path;
use std::ffi::OsStr;

fn get_extension_from_filename(filename: &str) -> Option<&str> {
    Path::new(filename)
        .extension()
        .and_then(OsStr::to_str)
}

assert_eq!(get_extension_from_filename("abc.gz"), Some("gz"));

Using and_then is convenient here because it means you don't have to unwrap the Option<&OsStr> returned by extension() and deal with the possibility of it being None before calling to_str . 使用and_then在这里很方便,因为这意味着你不必打开extension()返回的Option<&OsStr>并在调用to_str之前处理它是None的可能性。 I also could have used a lambda |s| s.to_str() 我也可以使用lambda |s| s.to_str() |s| s.to_str() instead of OsStr::to_str - it might be a matter of preference or opinion as to which is more idiomatic. |s| s.to_str()而不是OsStr::to_str - 它可能是一个偏好或意见的问题,哪个更惯用。

Notice that both the argument &str and the return value are references to the original string slice created for the assertion. 请注意,参数&str和返回值都是对为断言创建的原始字符串切片的引用。 The returned slice cannot outlive the original slice that it is referencing, so you may need to create an owned String from this result if you need it to last longer. 返回的切片不能超过它引用的原始切片,因此如果需要更长的时间,可能需要从此结果创建一个拥有的String

什么比使用Rust的内置方法更惯用?

Path::new(&filename).extension()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM