为什么编译代码需要这些确切的生命周期?

时间:2018-06-08 11:08:58

标签: rust lifetime borrow-checker

我正在编写一个解析器,需要一个迭代器的先行,但不想使用Peekable特征。相反,我使用了迭代器的包装器。我想出了类似的东西,省略了一切不必要的东西:

struct Wrapper<'a> {
    it: &'a mut Iterator<Item = &'a String>,
}

pub trait DoSomething {
    fn do_something(self);
}

impl<'a, T> DoSomething for T
where
    T: IntoIterator<Item = &'a String>,
{
    fn do_something(self) {
        let mut it = self.into_iter();
        let throwaway = Wrapper { it: &mut it };
    }
}

无法编译:

error[E0309]: the associated type `<T as std::iter::IntoIterator>::IntoIter` may not live long enough
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as std::iter::IntoIterator>::IntoIter: 'a`...
note: ...so that the type `<T as std::iter::IntoIterator>::IntoIter` is not borrowed for too long
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^

error[E0309]: the associated type `<T as std::iter::IntoIterator>::IntoIter` may not live long enough
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as std::iter::IntoIterator>::IntoIter: 'a`...
note: ...so that the type `<T as std::iter::IntoIterator>::IntoIter` will meet its required lifetime bounds
  --> src/main.rs:15:39
   |
15 |         let throwaway = Wrapper { it: &mut it };
   |                                       ^^^^^^^

虽然我不明白为什么这是必要的(问题1),但我将T::IntoIter: 'a添加到impl中的where子句中。这失败了:

error[E0597]: `it` does not live long enough
  --> src/main.rs:16:44
   |
16 |         let throwaway = Wrapper { it: &mut it };
   |                                            ^^ borrowed value does not live long enough
17 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 9:1...
  --> src/main.rs:9:1
   |
9  | / impl<'a, T> DoSomething for T
10 | | where
11 | |     T: IntoIterator<Item = &'a String>,
12 | |     T::IntoIter: 'a,
...  |
17 | |     }
18 | | }
   | |_^

我不明白为什么it的活动时间不够长,因为释放顺序应该是throwaway然后是it。使用第二个生命周期'b也不起作用,无论是使用'a: 'b还是使用'b: 'a(我感到很沮丧,只是尝试了每个组合)。

唯一有帮助的是将Iterator引用的生命周期与其包含的引用分开并将它们相关联(无需指定T::IntoIter的生命周期):

struct Wrapper<'a, 'b: 'a> {
    it: &'a mut Iterator<Item = &'b String>,
}

为什么?

说“项目引用必须至少和迭代器引用一样长”是有道理的,但是我没有得到的是为什么它们不能相同以及为什么错误消息暗示Wrapper构造而不是定义,其中改变生命周期根本没有帮助。

我发现关于生命时间的官方文​​档非常令人困惑。如果生命周期注释实际上改变了编译代码中有关重新分配的任何内容,或者它只是帮助静态分析而不实际改变内存的实际生命周期,则不会进入。

1 个答案:

答案 0 :(得分:1)

&'a mut Iterator<Item = &'a String>意味着迭代器引用的生命周期和迭代器返回的引用必须能够统一(到'a)。

声明迭代器和迭代器的引用具有不同的生命周期允许代码编译:

struct Wrapper<'i, 's: 'i> {
    it: &'i mut Iterator<Item = &'s String>,
}

无需添加T::IntoIter: 'a

另见:

相关问题