< 返回版块

坚果修补匠 发表于 2021-02-08 23:37

我在尝试用Rust实现一个单链表,在实现向尾部插入元素的时候rust报了错误,错误说发生了两次可变借用。可是第一个可变借用应该在第二次可变借用后就到期了啊。不太能理解错误的原因,请指教。部分源码如下

type Link<T> = Option<Box<Node<T>>>;

#[derive(Debug)]
pub struct LinkList<T> {
    head: Link<T>,
}

#[derive(Debug)]
struct Node<T> {
    ele: T,
    next: Link<T>,
}

impl<T> LinkList<T> {
   ...
   pub fn push_back(&mut self, ele :T) {
        let new_node = Node {
            ele: ele,
            next: None
        };
        match self.head.as_mut() {
            None => {self.head = Link::Some(Box::new(new_node))}
            Some(mut ptr) => { 
                while let Some(next_link) = &mut ptr.next{ //first
                    ptr = next_link;
                }
                ptr.next.replace(Box::new(new_node)); // second
            }
        }
    }
}

错误提示

error[E0499]: cannot borrow `ptr.next` as mutable more than once at a time
  --> src/linklist.rs:31:17
   |
28 |                 while let Some(next_link) = &mut ptr.next{
   |                                             ------------- first mutable borrow occurs here
...
31 |                 ptr.next.replace(Box::new(new_node));
   |                 ^^^^^^^^
   |                 |
   |                 second mutable borrow occurs here
   |                 first borrow later used here

error: aborting due to previous error

评论区

写评论
作者 坚果修补匠 2021-02-09 11:51

感谢各位大大。

Cupnfish 2021-02-09 11:45

Option实现Copy是有限制的:

impl<T> Copy for Option<T> where
    T: Copy, 

所以能通过的原因绝对不是因为这个,因为在本例中,Node<T>没有实现Copy,所以,此时的Option<Node<T>>自然也没有实现Copy。 这里能有效的原因其实是使用了ref,正常情况下的模式匹配,属于消耗匹配的值,也就是说匹配的过程当中发生了move,而使用了ref能够指明在匹配的时候不move仅仅借用。 关于ref的具体文档,请看这里:https://doc.rust-lang.org/stable/std/keyword.ref.html

--
👇
zhylmzr: 大概能理解这样写能通过的原因了. 因为Option实现了Copy, 所以这一行是copy moveptr了, 自然不存在一个值多次的可变借用.

while let Some(next_link) = &mut ptr.next{ //first
    ptr = next_link;
}

原本的写法, ptr.next被可变借用到了next_link, next_link又被move到ptr, 那么ptr.next的可变借用生命周期和ptr相同. 而ptr就是作为可变借用定义的, 所以在while之后访问ptr就会出现二次可变借用了.

--
👇
zhylmzr:

while let Some(ref mut next_link) = ptr.next{ //first
    ptr = next_link;
}

改成这样就可以了, 具体的原因我也不是很清楚, 等大佬解答

zhylmzr 2021-02-09 01:20

大概能理解这样写能通过的原因了. 因为Option实现了Copy, 所以这一行是copy moveptr了, 自然不存在一个值多次的可变借用.

while let Some(next_link) = &mut ptr.next{ //first
    ptr = next_link;
}

原本的写法, ptr.next被可变借用到了next_link, next_link又被move到ptr, 那么ptr.next的可变借用生命周期和ptr相同. 而ptr就是作为可变借用定义的, 所以在while之后访问ptr就会出现二次可变借用了.

--
👇
zhylmzr:

while let Some(ref mut next_link) = ptr.next{ //first
    ptr = next_link;
}

改成这样就可以了, 具体的原因我也不是很清楚, 等大佬解答

zhylmzr 2021-02-09 01:03
while let Some(ref mut next_link) = ptr.next{ //first
    ptr = next_link;
}

改成这样就可以了, 具体的原因我也不是很清楚, 等大佬解答

IWANABETHATGUY 2021-02-09 00:39
#[derive(Debug)]
pub struct LinkList<T> {
    head: Link<T>,
}

#[derive(Debug)]
struct Node<T> {
    ele: T,
    next: Link<T>,
}

impl<T> LinkList<T> {
    pub fn push_back(&mut self, ele: T) {
        let new_node = Node { ele, next: None };
        match self.head.as_mut() {
            None => self.head = Link::Some(Box::new(new_node)),
            Some(mut ptr) => {
                loop {
                    if let Some(ref mut next_link) = ptr.next {
                        ptr = next_link;
                    } else {
                        break;
                    }
                }
                ptr.next.replace(Box::new(new_node));
            }
        }
    }
}


1 共 5 条评论, 1 页