为什么变量的生命周期不够长?

9
考虑这个函数,它应该返回给定 Path 的文件扩展名。
pub fn get_extension<'a>(path: &'a Path) -> Option<&'a str> {
    let path_str = path.as_str().unwrap();
    let ext_pos = regex!(".[a-z0-9]+$").find(path_str);

    match ext_pos {
        Some((start, _)) => {
            return Some(path_str.as_slice().slice_from(start))
        },
        None => return None
    }
}

错误信息如下:
`path_str` does not live long enough

输入图像说明

错误信息很清楚,可惜我自己无法解决。理论上我理解,但仍有一些模糊的地方。

我理解编译器要告诉我path_str的寿命不足以作为标记有生命周期'a的返回值有效。

但这就是我的疑问所在:

  • 我明白对path(输入参数)的引用应该恰好与包含在Option(输出参数)中的str的引用相同寿命。

  • 由于我们返回Some(path_str.as_slice().slice_from(start)),实际上意味着path_str需要和path具有相同的寿命。

我不明白的是为什么path_str的生命周期不够长,我该如何修复?是什么导致它过早死亡?

更新

正如评论中指出的,并且在IRC上也指出,去掉多余的as_slice()使代码编译通过。有人知道原因吗?还指出存在一个方法可以直接获取扩展名。但是,我更想了解问题的背后故事。


1
Path_str已经是一个切片,所以您可以删除as_slice并且它将正常工作。这可能是一个错误。 - Arjan
谢谢。那个方法很有效。我会相应地更新问题。 - Christoph
1个回答

12
这不是一个bug。问题在于as_slice的定义。它获取参数的引用并返回一个&str,该字符串的生命周期与引用相同,它无法检查调用它的类型的内部生命周期。也就是说,path_str.as_slice()返回一个&str,其持续时间与path_str一样长,而不是指向数据的path_str(原始Path)的持续时间。
换句话说,这里有两个生命周期。我将在@Arjan的filed bug示例中使用一个假设的块生命周期注释语法(本答案基于my response there)。
fn test<'a>(s: &'a String) -> &'a str {
    'b: {
        let slice: &'a str = s.as_slice();
        slice.as_slice()
    }
}

针对第二个as_slice调用,我们有self: &'b &'a str,因此它返回的是&'b str,但它太短了:'b只是局部于test
如您所发现的那样,现在的修复方法只需删除多余的as_slice调用即可。但是,使用动态大小类型(DST),我们将能够编写impl StrSlice for str,然后slice.as_slice()将会返回一个&'a str,因为不会有额外的引用层(也就是说,self: &'a str)。

那么,有了 Str trait 的这个等效定义:http://is.gd/L4yATO,那么这个类型签名怎么不是一个谎言呢? - Arjan
@Arjan 您指的是哪种类型签名?fn as_slice2<'a>(&'a self) -> &'a str - huon
是的,它声称返回具有生命周期“a”的东西,但*self的生命周期为“b”。或者它是否推断出“a < b”,这使它有效? - Arjan
但它无法推断 'a == 'b? - Arjan
1
它演示了引用在实践中的工作原理。您创建引用的位置 - 在这种情况下,您调用方法时它会生成一个&self - 是该引用的“锚定点”。 - bluss
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接