基于堆栈的链表:可变借用的范围

问题描述 投票:0回答:1
use std::{fmt::Display, ops::Deref};

#[derive(Debug, Clone, Copy)]
struct StackNode<'a, T> {
    data: &'a T,
    next: Option<&'a StackNode<'a, T>>,
}

impl<'a, T> StackNode<'a, T> {
    fn new(data: &'a T, next: Option<&'a StackNode<'a, T>>) -> Self {
        Self { data, next }
    }

    pub fn len(&self) -> usize {
        self.into_iter().count()
    }

    fn insert(&mut self, sn: &'a mut Self) -> &mut Self {
        match self.next {
            Some(_) => {
                sn.next = self.next;
                self.next = Some(sn);
            }
            None => {
                self.next = Some(sn);
            }
        }
        self
    }
}

impl<'a, T> Deref for StackNode<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        self.data
    }
}

pub struct RefNodeIterator<'a, T> {
    current: Option<&'a StackNode<'a, T>>,
}

impl<'a, T> Iterator for RefNodeIterator<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        match self.current {
            Some(node) => {
                self.current = node.next;
                Some(node.data)
            }
            None => None,
        }
    }
}

impl<'a, T> IntoIterator for &'a StackNode<'a, T> {
    type Item = &'a T;
    type IntoIter = RefNodeIterator<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        RefNodeIterator {
            current: Some(self),
        }
    }
}

impl<'a, T: Display> Display for StackNode<'a, T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut repr = String::new();
        let mut iter = self.into_iter();
        loop {
            match iter.next() {
                Some(d) => {
                    repr += &format!("{d} --> ");
                }
                None => {
                    repr += "NULL";
                    break;
                }
            }
        }
        write!(f, "{repr}")
    }
}
#[test]
fn insert() {
    let data = (0..4)
        .into_iter()
        .map(|i| format!("{i}"))
        .collect::<Vec<_>>();

    let mut data_iter = data.iter();

    let mut n0 = StackNode::new(data_iter.next().unwrap(), None);

    let mut n1 = StackNode::new(data_iter.next().unwrap(), None);
    n0.insert(&mut n1);

    let mut n2 = StackNode::new(data_iter.next().unwrap(), None);
    n1.insert(&mut n2); // this does NOT work
    n0.insert(&mut n2); // this works. why ?

    let mut n3 = StackNode::new(data_iter.next().unwrap(), None);
    n0.insert(&mut n3);

    assert_eq!(n0.to_string(), "0 --> 3 --> 2 --> 1 --> NULL");
}
cargo t --tests
   Compiling smart_pointers v0.1.0 (/home/akash/Programming/rust/projects/smart_pointers)
error[E0499]: cannot borrow `n1` as mutable more than once at a time
   --> src/test/stack_linked_list.rs:115:5
    |
112 |     n0.insert(&mut n1);
    |               ------- first mutable borrow occurs here
...
115 |     n1.insert(&mut n2);
    |     ^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
118 |     n0.insert(&mut n3);
    |     ------------------ first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `smart_pointers` (bin "smart_pointers" test) due to previous error

在上面的代码片段中,第一个借位使用在哪里,而第二个借位用于 n1? rust 编译器是否将 n1 的第一个可变借用的范围扩展到 n0 的范围?这就是为什么 n1 的第二次借用不被允许的原因吗?目前还不清楚 rust 编译器如何从错误消息中推断出借用的长度。 Rust 到底是如何推断出可变借用的持续时间/范围的?

rust linked-list
1个回答
0
投票

sn
方法中可变借用
insert
的存储可能会导致
n1
可变借用的范围扩展到整个测试函数的范围。这是因为节点本身包含从 vec 借用的内容,这迫使 Rust 延长
n0
的持续时间范围,从而延长
n1
的持续时间范围,因为它存储在其中。

© www.soinside.com 2019 - 2024. All rights reserved.