考虑这个应该返回给定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
的有效期不够长,因为返回值标有life 'a
。
但这就是它停止的地方:
我理解对path
(输入参数)的引用应该与str
中包含的Option
的引用完全一样长(输出)参数)
因为我们返回Some(path_str.as_slice().slice_from(start))
我认为实际上这意味着path_str
只需path
就可以生存。
我不明白的是为什么 path_str
不能活得足够长,我该如何解决这个问题?是什么让它很快死去?
更新
正如评论中指出的那样,以及IRC删除超级as_slice()
使得代码编译。有谁知道那是为什么?还有人指出,存在method直接获得扩展。但是,我真的对学习问题背后的故事更感兴趣。
答案 0 :(得分:12)
这不是错误。这里的“问题”是as_slice
的定义。它引用了它的参数,并返回一个与引用具有相同生命周期的&str
,它无法反省它被调用的任何类型的内部生命周期。也就是说,只要数据path_str.as_slice()
指向({1}},&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
电话。但是,使用dynamically sized types (DST),我们可以写impl StrSlice for str
,然后slice.as_slice()
将返回&'a str
,因为不会是一个额外的引用层(即self: &'a str
)。