3

私はRustを学んでいて、双方向リンクリストをコーディングしてみました。しかし、私はすでに典型的な反復トラバーサルの実装に行き詰まっています。ボロー チェッカー/ドロップ チェッカーが厳しすぎて、ボローが から関数の境界を越えたときに、ボローの正しい有効期間を推測できないという印象を受けていますRefCellcurr変数バインディング (この場合) を現在のコンテンツの借用に繰り返し設定する必要があります。

use std::cell::RefCell;
use std::rc::Rc;

pub struct LinkedList<T> {
    head: Option<Rc<RefCell<LinkedNode<T>>>>,
    // ...
}

struct LinkedNode<T> {
    value: T,
    next: Option<Rc<RefCell<LinkedNode<T>>>>,
    // ...
}

impl<T> LinkedList<T> {
    pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
        // ... some logic ...

        // This is the traversal that fails to compile.
        let mut curr = self.head.as_ref().unwrap();
        for _ in 1..idx {
            curr = curr.borrow().next.as_ref().unwrap()
        }

        // I want to use curr here.
        // ...
        unimplemented!()
    }
}

コンパイラは不平を言います:

NLLなし

error[E0597]: borrowed value does not live long enough
  --> src/lib.rs:22:20
   |
22 |             curr = curr.borrow().next.as_ref().unwrap()
   |                    ^^^^^^^^^^^^^ temporary value does not live long enough
23 |         }
   |         - temporary value dropped here while still borrowed
...
28 |     }
   |     - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

NLLあり

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:22:20
   |
22 |             curr = curr.borrow().next.as_ref().unwrap()
   |                    ^^^^^^^^^^^^^
   |                    |
   |                    creates a temporary which is freed while still in use
   |                    a temporary with access to the borrow is created here ...
23 |         }
   |         -
   |         |
   |         temporary value is freed at the end of this statement
   |         ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
   |
   = note: consider using a `let` binding to create a longer lived value
   = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.

この問題に対する反復的な解決策非再帰的)を本当に感謝します。

4

2 に答える 2

1

これは、同じ問題を示していると思われる小さな複製です。

use std::cell::RefCell;

fn main() {
    let foo = RefCell::new(Some(42));
    let x = foo.borrow().as_ref().unwrap();
}

私がそれを読んだとき:

  1. foo.borrow()は、スマート ポインタcell::Refの一種である を返します。この場合、スマート ポインターは.&Option<i32>
  2. as_ref()Option<&i32>内部参照がスマート ポインターと同じ有効期間を持つを作成します。
  3. Option破棄され、 のみが生成され&i32ますが、スマート ポインターの有効期間は残ります。

特に、スマート ポインターはステートメントの間だけ持続しますが、コードは、ステートメントよりも長くRef存続する への参照を返そうとします。Ref

一般的に、解決策は次のようにすることです。

let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();

foo_borrowこれにより、スマート ポインターが長く保持され、 (借用自体を表す) 存在する限り、参照の有効期間が有効になります。

ループの場合、基本的に次のノードに到達するまで前のノードをすべて借用する必要があるため、できることはあまりありません。

于 2016-04-13T13:05:28.077 に答える