Why

lifetime parameter代表着变量的引用的生命周期,在一些代码中,会看到一个函数有多个lifetime变量,如何理解?

考虑这样一个函数

  1. pub struct StrSplit<'a> {
  2. remainder: &'a str,
  3. delimiter: &'a str,
  4. }
  5. impl<'a> StrSplit<'a> {
  6. pub fn new(haystack: &'a str, delimiter: &'a str) -> Self {
  7. Self {
  8. remainder: haystack,
  9. delimiter,
  10. }
  11. }
  12. pub fn next(&mut self) -> Option<&'a str> {
  13. if let Some(next_delim) = self.remainder.find(self.delimiter) {
  14. let until_delimter = &self.remainder[..next_delim];
  15. self.remainder = &self.remainder[(next_delim + self.delimiter.len())..];
  16. Some(until_delimiter)
  17. } else if self.remainder.is_empty() {
  18. None
  19. } else {
  20. let rest = self.remainder;
  21. self.remainder = "";
  22. Some(rest)
  23. }
  24. }
  25. }
  26. fn main() {
  27. let heystack = "a b c d e".to_string();
  28. let letters = StrSplit::new(&heystack, " ");
  29. assert_eq!("a", letters.next());
  30. }

这里我们定义了一个结构体 StrSplit, 它的两个字段拥有相同的lifetime,乍一看这里没有什么问题,并且从测试函数来看也没问题,但这时候考虑另外一种情况 s

  1. fn until_char(s: &str, c: char) -> Option<&str> {
  2. let delimter = format!("{}", c);
  3. StrSplit::new(s, &delimter).next()
  4. }
  5. fn main() {
  6. let heystack = "a b c d e".to_string();
  7. let res = until_char(&heystack, ' ');
  8. assert_eq!("a", res);
  9. }
  1. error[E0515]: cannot return value referencing local variable `delimter`
  2. --> src/lib.rs:41:5
  3. |
  4. 41 | StrSplit::new(s, &delimter).next()
  5. | ^^^^^^^^^^^^^^^^^---------^^^^^^^^
  6. | | |
  7. | | `delimter` is borrowed here
  8. | returns a value referencing data owned by the current function
  9. error: aborting due to previous error
  10. 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

  1. pub struct StrSplit<'a, 'b> {
  2. remainder: &'a str,
  3. delimiter: &'b str,
  4. }
  5. impl<'a, 'b> StrSplit<'a, 'b> {
  6. pub fn new(haystack: &'a str, delimiter: &'b str) -> Self {
  7. Self {
  8. remainder: haystack,
  9. delimiter,
  10. }
  11. }
  12. }

这样就告诉编译器,haystack和delimiter的liftime不一致,但是返回值的lifetime和haystack一样。