簡體   English   中英

Rust:在遞歸 Function 中使用可變引用

[英]Rust: Use of Mutable References in Recursive Function

我正在嘗試使用遞歸 function 打印Vec的唯一連續子數組,如下所示:

use std::collections::HashSet;

fn recurse<'a>(nums: &'a [i32], already_printed: &'a mut HashSet<&'a [i32]>) {
    if !already_printed.contains(nums) {
        println!("{:#?}", nums);
    }

    already_printed.insert(nums);

    if nums.len() >= 2 {
        recurse(&nums[0..nums.len() - 1], already_printed);
        recurse(&nums[1..nums.len()], already_printed);
    }
}

pub fn main() {
    let k = vec![1, 2, 3, 4, 5];
    let mut already_printed: HashSet<&[i32]> = HashSet::new();
    recurse(&k[0..], &mut already_printed);
}

當然,正如經驗豐富的 Rustaceans 可能已經猜到的那樣,編譯失敗並出現以下錯誤:

error[E0499]: cannot borrow `*already_printed` as mutable more than once at a time
  --> src/main.rs:12:39
   |
3  | fn recurse<'a>(nums: &'a [i32], already_printed: &'a mut HashSet<&'a [i32]>) {
   |            -- lifetime `'a` defined here
...
11 |         recurse(&nums[0..nums.len() - 1], already_printed);
   |         --------------------------------------------------
   |         |                                 |
   |         |                                 first mutable borrow occurs here
   |         argument requires that `*already_printed` is borrowed for `'a`
12 |         recurse(&nums[1..nums.len()], already_printed);
   |                                       ^^^^^^^^^^^^^^^ second mutable borrow occurs here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.

我從非常有用的錯誤中理解了為什么編譯器拒絕編譯它。 但是,一般來說,實現上述代碼中采用可變引用的遞歸函數的解決方法是什么?

我能想到的一種可能的解決方法是使用內部可變性模式à la RefCell

use std::cell::RefCell;
use std::collections::HashSet;

fn recurse<'a>(nums: &'a [i32], already_printed: &'a RefCell<HashSet<&'a [i32]>>) {
    if !already_printed.borrow().contains(nums) {
        println!("{:#?}", nums);
    }

    already_printed.borrow_mut().insert(nums);

    if nums.len() >= 2 {
        recurse(&nums[0..nums.len() - 1], already_printed);
        recurse(&nums[1..nums.len()], already_printed);
    }
}

pub fn main() {
    let k = vec![1, 2, 3, 4, 5];
    let already_printed: HashSet<&[i32]> = HashSet::new();
    let ref_cell: RefCell<HashSet<&[i32]>> = RefCell::new(already_printed);
    recurse(&k[0..], &ref_cell);
}

雖然這可行,但這似乎放棄了編譯時借用檢查器提供的安全軌。 是否有不同的規范方法來進行遞歸 function 調用,同時仍然通過編譯時間借用檢查器?

神奇的解決方案是將 function 的聲明更改為

fn recurse<'a, 'b>(nums: &'a [i32], already_printed: &'b mut HashSet<&'a [i32]>) {
// I just changed this lifetime -----------------------^

您的算法無法正常工作並沒有深層原因,只是您在沒有理由的情況下添加了太多約束。

當您從內部調用recurse時,它完全recurse問題,因為它在通話結束時釋放了所有權。 所以它必須工作。

但是您要求所有生命周期都相同,而您可以讓編譯器確定真正的約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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