![](/img/trans.png)
[英]Cannot infer an appropriate lifetime for autoref due to conflicting requirements
[英]`cannot infer an appropriate lifetime for autoref due to conflicting requirements` but can't change anything due to trait definition constraints
我通過跟蹤太多的鏈表來實現鏈表。 在嘗試實現iter_mut()
時,我自己做了並編寫了以下代碼:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::<T>(&mut self.head)
}
}
pub struct IterMut<'a, T>(&'a mut Link<T>);
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.as_mut().map(|node| {
self.0 = &mut (**node).next;
&mut (**node).elem
})
}
}
我要避免強制和省略,因為明確可以讓我理解更多。
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/third.rs:24:16
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 23:13...
--> src/third.rs:23:13
|
23 | fn next<'b>(&'b mut self) -> Option<&'a mut T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:24:9
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 20:6...
--> src/third.rs:20:6
|
20 | impl<'a, T> Iterator for IterMut<'a, T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:25:22
|
25 | self.0 = &mut (**node).next;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
由於需求沖突,我查看了無法推斷 autoref 的適當生命周期。
我懂一點,但不多。 我在這里面臨的問題是,如果我嘗試更改任何內容,則會彈出一個錯誤,指出與特征定義不匹配。
我的想法是,基本上我需要 state 以某種方式生命'b
比'a
壽命更長,即<'b: 'a>
但我不知道該怎么做。 此外,我有類似的功能來實現iter()
效果很好。 它讓我感到困惑為什么iter_mut()
會產生這樣的錯誤。
type Link<T> = Option<Box<Node<T>>>;
pub struct Iter<'a, T>(&'a Link<T>);
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.as_ref().map(|node| {
self.0 = &((**node).next);
&((**node).elem)
})
}
}
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter::<T>(&self.head)
}
}
☝️這行得通。
關鍵是您需要能夠以某種方式從 a &'b mut IterMut<'a, T>
中提取Option<&'a mut T>
> 。
要了解為什么IterMut<'a, T>:= &'a mut Link<T>
不能工作,您需要了解使用可變引用到底可以做什么。 當然,答案幾乎是一切。 您可以從中復制數據、更改其值以及許多其他事情。 您不能做的一件事是使其無效。 如果要將可變引用下的數據移出,則必須將其替換為相同類型的內容(包括生命周期)。
在next
的主體內, self
(本質上)是&'b mut &'a mut Link<T>
。 除非我們對T
有所了解(在這種情況下我們不知道),否則根本無法從中生成&'a mut Link<T>
類型的東西。 例如,如果這在一般情況下是可能的,我們就可以做到
fn bad<'a, 'b, T>(_x: &'b mut &'a mut T) -> &'a mut T {
todo!()
}
fn do_stuff<'a>(x: &'a mut i32, y: &'a mut i32) {
// lots of stuff that only works if x and y don't alias
*x = 13;
*y = 42;
}
fn main() {
let mut x: &mut i32 = &mut 0;
let y: &mut i32 = {
let z: &mut &mut i32 = &mut x;
bad(z)
};
// `x` and `y` are aliasing mutable references
// and we can use both at once!
do_stuff(x, y);
}
關鍵是,如果我們能夠在較短的(通用)生命周期'b
中借用某些東西並返回允許在較長生命周期'a
期間進行修改的東西,我們將能夠使用多個較短的生命周期(比'a
和非-overlapping) 以獲取具有相同生命周期的多個可變引用'a
。
這也解釋了為什么不可變版本有效。 對於不可變引用,從&'b &'a T
到&'a T
到 go 是微不足道的:只需尊重並復制不可變引用。 相比之下,可變引用不實現Copy
。
因此,如果我們不能從 a &'b mut &'a mut Link<T>
&'a mut Link<T>
我們當然也不能從中得到Option<&'a mut T
(除了None
)。 (請注意,我們可以生成一個&'b mut Link<T>
並因此生成一個Option<'b mut T>
。這就是您的代碼現在所做的。)
那么有什么作用呢? 請記住,我們的目標是能夠從 a &'b mut IterMut<'a, T>
生成Option<&'a mut T>
> 。
如果我們能夠無條件地生成一個IterMut<'a, T>
,我們將能夠(暫時)用它替換self
,因此能夠直接訪問與我們的列表關聯的IterMut<'a, T>
。
// This actually type-checks!
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = todo!(); // obviously this won't work
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.as_mut().map(|node| {
self.0 = &mut node.next;
&mut node.elem
})
}
進行設置以使這一切正常進行的最簡單方法是稍微轉置IterMut<'a, T>
。 與其將可變引用放在選項之外,不如將其放在里面! 現在,您將始終能夠生成帶有None
的IterMut<'a, T>
!
struct IterMut<'a, T>(Option<&mut Box<Node<T>>>);
next
翻譯,我們得到
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = IterMut(None);
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
更慣用的是,我們可以使用Option::take
而不是std::mem::swap
(這在Too Many Linked Lists前面提到過)。
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.take().map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
這實際上與Too Many Linked Lists中的實現略有不同。 該實現刪除了&mut Box<Node<T>>
的雙重間接,並將其替換為簡單的&mut Node<T>
。 但是,我不確定您獲得了多少,因為該實現在List::iter_mut
和Iterator::next
中仍然具有雙重 deref。
Rust 試圖說你有一個懸空的參考。
self.0.as_mut() // value borrowed
self.0 = <> // underlying value changed here.
問題是以下定義:
pub struct IterMut<'a, T>(&'a mut Link<T>)
這不能封裝您將有一個“空”節點,這意味着到達節點的末尾。
使用書中提到的結構,如:
pub struct IterMut<'a, T>(Option<&'a mut Node<T>>);
這確保了當您運行 end of list 並使用take
在后台修改 IterMut 內容時,您可以將 None 保留在其位置。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.