我遇到了在具有生命周期约束的类型上实现 Index
的问题 . 我有一个 SubImage
结构,其中包含对 Image
的引用 . 我找不到满足编译器的任何方法 .
impl<'a, P> Index<usize> for SubImage<'a, P> {
type Output = [P];
fn index<'b> (&'b self, y: usize) -> &'b [P] {
let start = (self.rect.y0 + y) * self.image.size.x + self.rect.x0;
let end = start + self.rect.width();
&self.image.buf[start..end]
}
}
'a
是引用图像的生命周期,因此切片其缓冲区需要此约束 . 这里的代码编译,但它是模糊的 . 对索引运算符的所有调用都会产生一条错误消息,例如:
src/image.rs:179:13: 179:32 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
src/image.rs:179 Some(&self.sub[self.back])
^~~~~~~~~~~~~~~~~~~
src/image.rs:174:3: 181:4 help: consider using an explicit lifetime parameter as shown: fn next_back(&'a mut self) -> Option<&'a [P]>
src/image.rs:174 fn next_back (&mut self) -> Option<&'a [P]> {
src/image.rs:175 if self.front == self.back {
src/image.rs:176 None
src/image.rs:177 } else {
src/image.rs:178 self.back -= 1;
src/image.rs:179 Some(&self.sub[self.back])
是否有任何可能的方法来确保返回值被约束到 'a
和 'b
或在这种情况下正确实现 Index
的其他方式?编译器's suggestion doesn' t工作,因为函数签名与特征的签名不匹配 .
1 回答
实际上你的问题更多,而不是Index trait实现 . 此外,您的示例并非真正的最小,完整且可验证的示例(MCVE),因此我必须猜测您的确切问题在这里 .
你的问题的核心是,你不能让你的迭代器返回一个引用,如果它拥有内容而不借用迭代器本身 . 你为SubImage实现Index特性是好的 .
我会尝试模拟你的问题 . 假设我们有一个结构Julmond,它借用了一些整数(类似于你的SubImage) .
指数特征要求我们借用自我 . 这很好,因为一些实现者可能拥有您正在索引的数据 . 这种自我的借用是通过将自我的命名生命期和特征_613694中的传出引用联系起来表达的:
如果我们索引到Julmond,那么只要我们坚持将结果引用到Julmond中,该值就被认为是借用的:
我可以从您的示例代码中读到的是,您拥有一些拥有SubImage并实现Iterator特征的类型 . 我们将尝试模仿另一个结构Nebelung在路上实现Iterator特性:
此实现从基础Julmond结构返回一个不断缩小的数组切片 . 我们可以这样测试:
但这不起作用 . 编译器会抱怨(如在你的例子中)它无法推断'a'的适当生命周期 . 原因是在索引方法中借用self . 当我们用j [tmp_pos]调用索引运算符时,我们正在借用j . 但是j由Nebelung类型的自己拥有,因此从j借用意味着我们从自己借用 . 我们试图返回对自己拥有的东西的引用,并且要求自己也必须借用 . 编译器建议正确的事情:链接self和传出引用的生命周期 . 但是,这违反了下一步的方法签名 .
如果我们想从迭代器返回一个引用,那么迭代器不能拥有返回的值 . 否则,我们将不得不在调用中借用迭代器,但接下来是不可能的 .
解决这个问题的唯一方法是让迭代器不拥有值 . 所以我们修改了Nebelung结构来保存对Julmond的引用:
'a:'b表示“'a outlives'b”,这里需要它 . 由于我们对Julmond的引用j不得超过Julmond的借用内容 . 好的,我们的Nebelung不再是Julmond的老板了 . 只是一个借款人 . 现在我们可以像这样实现Iterator特性:
自我和传出引用的生命周期不需要链接,因为我们只是返回一个我们不是所有者的某个值的引用 . 所以对&self.j [tmp_pos]的调用不再是对自己的借用了 . 它是从Julmond借来的(通过索引实现) .
Complete example
无论你为什么类型实现Iterator特性 . 如果类型拥有该值,则不能让next(或next_back)返回引用 . 让您的类型借用SubImage .