我试图从给定的字符串路径中提取文件的扩展名.

下面的代码是有效的,但我想知道是否有更干净的idiomatic Rust way多个代码可以实现这一点:

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");

}

推荐答案

在习惯用法中,可能失败的函数的返回类型应该是OptionResult.通常,函数也应该接受切片而不是String,并且只在必要时创建新的String.这减少了过度的复制和堆分配.

您可以使用提供的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"));

在这里使用and_then很方便,因为这意味着你不必打开extension()返回的Option<&OsStr>,在拨打to_str之前处理None的可能性.我也可以用lambda |s| s.to_str()而不是OsStr::to_str——这可能是一个偏好或观点的问题,哪一个更为惯用.

请注意,参数&str和返回值都是对为断言创建的原始字符串片段的引用.返回的切片不能比它引用的原始切片更长寿,因此如果需要更长时间,可能需要根据该结果创建一个新的切片.

Rust相关问答推荐

给定使用newype习语定义的类型上的铁 rust Vec,有没有方法获得底层原始类型的一部分?

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

如何使用字符串迭代器执行查找?

有没有办法模仿对象安全克隆?

如何在Bevy/Rapier3D中获得碰撞机的计算质量?

在自定义序列化程序中复制serde(With)的行为

除了调用`waker.wake()`之外,我如何才能确保future 将再次被轮询?

如何将单个 struct 实例与插入器一起传递到Rust中的映射

为什么 vec![Vec::with_capacity(n)] 为子向量创建 0 容量?

处理带有panic 的 Err 时,匹配臂具有不兼容的类型

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

在 Bevy 项目中为 TextureAtlas 精灵实施 NearestNeighbor 的正确方法是什么?

在运行时在 Rust 中加载字体

将 Futures 的生命周期特征绑定到 fn 参数

Rust 中函数的类型同义词

为什么 &i32 可以与 Rust 中的 &&i32 进行比较?

使用 serde_json 进一步处理字段

如何获得对数组子集的工作可变引用?

用逗号分隔字符串,但在标记中使用逗号

`if let` 只是另一种编写其他 `if` 语句的方式吗?