Consider this function that should return the file extension of a given 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
}
}
The error message is as follows:
`path_str` does not live long enough
The error message is pretty clear and it's a shame I can't work it out on my own. I understand it in theory but there are still a couple of blurred things for me.
I understand that the compiler wants to tell me that path_str
does not live long enough to be valid as the return value with is marked with lifetime 'a
.
But this is where it stops for me:
I understand that the reference to path
(the input parameter) should life exactly as long as the reference to the str
that is wrapped in the Option
(the output parameter)
since we return Some(path_str.as_slice().slice_from(start))
I assume that in practice that means that path_str
needs to live as long as path
.
What I don't understand is why exactly does path_str
not live long enough and how could I fix this? What makes it die to soon?
UPDATE
As pointed out in the comments and also on IRC removing the superflous as_slice()
makes the code compile. Does anyone know why that is? It was also pointed out that there exists a method to get the extension directly. But yep, I'm actually more interested in learning the story behind the problem though.
These word references cannot outlive the if let block, which means you cannot use them as keys in the hash map. The easiest fix is to have words_matches own its keys. Without borrows there are no lifetimes, and thus no lifetime issues.
A static is never "inlined" at the usage site, and all references to it refer to the same memory location. Static items have the static lifetime, which outlives all other lifetimes in a Rust program. Static items may be placed in read-only memory if the type is not interior mutable.
This isn't a bug. The "problem" here is as_slice
's definition. It takes a reference to its arguments, and returns a &str
with the same lifetime as the reference, it can't introspect into the internal lifetimes of whatever type it is being called on. That is, path_str.as_slice()
returns a &str
that lasts for as long as path_str
, not as long as the data path_str
points at (the original Path
).
In other words, there's two lifetimes here. I'll use a hypothetical block-lifetime annotation syntax on the example from @Arjan's filed bug (this answer is based of my response there).
fn test<'a>(s: &'a String) -> &'a str {
'b: {
let slice: &'a str = s.as_slice();
slice.as_slice()
}
}
For the second as_slice
call we have self: &'b &'a str
, and thus it returns &'b str
, which is too short: 'b
is just local to test
.
As you discovered, the fix now is just removing the extraneous as_slice
call. However, with dynamically sized types (DST), we will be able to write impl StrSlice for str
, and then slice.as_slice()
will be returning a &'a str
, since there won't be an extra layer of references (that is, self: &'a str
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With