Why
lifetime parameter代表着变量的引用的生命周期,在一些代码中,会看到一个函数有多个lifetime变量,如何理解?
考虑这样一个函数
pub struct StrSplit<'a> {
remainder: &'a str,
delimiter: &'a str,
}
impl<'a> StrSplit<'a> {
pub fn new(haystack: &'a str, delimiter: &'a str) -> Self {
Self {
remainder: haystack,
delimiter,
}
}
pub fn next(&mut self) -> Option<&'a str> {
if let Some(next_delim) = self.remainder.find(self.delimiter) {
let until_delimter = &self.remainder[..next_delim];
self.remainder = &self.remainder[(next_delim + self.delimiter.len())..];
Some(until_delimiter)
} else if self.remainder.is_empty() {
None
} else {
let rest = self.remainder;
self.remainder = "";
Some(rest)
}
}
}
fn main() {
let heystack = "a b c d e".to_string();
let letters = StrSplit::new(&heystack, " ");
assert_eq!("a", letters.next());
}
这里我们定义了一个结构体 StrSplit, 它的两个字段拥有相同的lifetime,乍一看这里没有什么问题,并且从测试函数来看也没问题,但这时候考虑另外一种情况 s
fn until_char(s: &str, c: char) -> Option<&str> {
let delimter = format!("{}", c);
StrSplit::new(s, &delimter).next()
}
fn main() {
let heystack = "a b c d e".to_string();
let res = until_char(&heystack, ' ');
assert_eq!("a", res);
}
error[E0515]: cannot return value referencing local variable `delimter`
--> src/lib.rs:41:5
|
41 | StrSplit::new(s, &delimter).next()
| ^^^^^^^^^^^^^^^^^---------^^^^^^^^
| | |
| | `delimter` is borrowed here
| returns a value referencing data owned by the current function
error: aborting due to previous error
For more information about this error, try `rustc --explain E0515`.
这个错告诉我们,返回值引用了local variable, 但是返回值明明引用的明明是heystack, 为什么说引用了delimter?因为我们在初始化StrSplit的时候告诉compiler, haystack: &'a str, delimiter: &'a str
haystack, delimiter拥有相同的lifetime,如果这两个参数lifetime不一样,那么编译器会选择最短的那个lifetime,在这个例子中,编译器发现 delimter的liftime在until_char这个函数结束后就销毁了,所以编译器选择了delimter的lifetime,并且由于next的返回值的lifetime也是 ‘a, 所以编译器认为 next的返回值和delimter的lifetime一致。
那要如何修改这个函数来解决这个问题?
在这里引入一个新的lifetime
pub struct StrSplit<'a, 'b> {
remainder: &'a str,
delimiter: &'b str,
}
impl<'a, 'b> StrSplit<'a, 'b> {
pub fn new(haystack: &'a str, delimiter: &'b str) -> Self {
Self {
remainder: haystack,
delimiter,
}
}
}
这样就告诉编译器,haystack和delimiter的liftime不一致,但是返回值的lifetime和haystack一样。