簡體   English   中英

`由於需求沖突,無法為 autoref 推斷適當的生命周期`,但由於特征定義約束,無法更改任何內容

[英]`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> 與其將可變引用放在選項之外,不如將其放在里面! 現在,您將始終能夠生成帶有NoneIterMut<'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_mutIterator::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM