当一个函数使用&self时,结构体成员的所有权归谁?

3
我希望能够写一个小的封装来包装 VecDeque
具体地,我有这段代码(playground):
use std::collections::VecDeque;

trait VecCircleTraits<T: Eq> {
    fn new() -> VecCircle<T>;
    fn find_and_remove(&self, _: T) -> Option<T>;
}

#[derive(Debug)]
struct VecCircle<T: Eq>(VecDeque<T>);

impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn new() -> VecCircle<T> {
        return VecCircle(VecDeque::<T>::new());
    }

    fn find_and_remove(&self, key: T) -> Option<T> {
        let search_index: Option<usize> = self.0.into_iter().position(|x| x == key); //error 1
        if let Some(index) = search_index {
            return self.0.remove(index); // error 2
        } else {
            return None;
        }
    }
}

这会给我以下错误:

    error: cannot borrow immutable anonymous field `self.0` as mutable
  --> <anon>:20:20
   |>
20 |>             return self.0.remove(index); // error 2
   |>                    ^^^^^^

error: cannot move out of borrowed content [--explain E0507]
  --> <anon>:18:44
   |>
18 |>         let search_index: Option<usize> =  self.0.into_iter().position(|x| x == key); //error 1
   |>                                            ^^^^ cannot move out of borrowed content

然而,我有点困惑,谁拥有self.0的所有权?如果我正确理解文档,那么内存区域不是被限制在self.0上,并因此归它所有吗?对于我的肤浅逻辑感到抱歉,但我仍在努力理解所有权系统。

2个回答

4
find_and_remove中,你在参数列表中指定了&self。这意味着该方法将接收到一个对self的借用指针;即self的类型为&VecCircle<T>。因此,该方法不拥有VecCircle<T>的所有权。 find_and_remove试图在一个VecDeque上调用into_iter,而into_iter通过值(self而不是&self&mut self)接收其参数。因此,Rust将self.0解释为尝试将VecDeque移动出VecCircle。然而,这是不允许的,因为不能从借用的内容中移动任何东西,因为从某个位置移动会使该位置无效。但我们不能只告诉调用者“嘿,我刚刚使self无效了,请停止使用它!”;如果我们想要这样做,我们必须在参数列表中指定self,而不是&self
但这不是你在这里尝试做的事情。 into_iter 会获取 VecDeque 的所有权,因此会销毁它。有其他方法可以获得 VecDeque 的迭代器而不销毁它。在这里,我们应该使用 iter,它接受 &self

然后,find_and_remove 尝试调用 removeremove 接受 &mut self,即对 VecDeque 的可变引用。但是,我们不能将 self.0 借为可变的,因为 self 本身不是一个可变借用。我们不能仅仅将不可变借用升级为可变借用:同时使用不可变借用和可变借用是无效的。解决方法是在参数列表中将 &self 更改为 &mut self

use std::collections::VecDeque;

trait VecCircleTraits<T: Eq> {
    fn new() -> VecCircle<T>;
    fn find_and_remove(&mut self, _: &T) -> Option<T>;
}

#[derive(Debug)]
struct VecCircle<T: Eq>(VecDeque<T>);

impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn new() -> VecCircle<T> {
        return VecCircle(VecDeque::<T>::new());
    }

    fn find_and_remove(&mut self, key: &T) -> Option<T> {
        let search_index: Option<usize> =  self.0.iter().position(|x| x == key);
        if let Some(index) =  search_index {
            self.0.remove(index)
        } else {
            None
        }
    }
}

注意:我还将key参数更改为&T,以解决传递给position的闭包中的另一个错误。由于iter迭代器迭代的是VecDeque中项目的引用,因此position会将引用传递给闭包。由于find_and_remove实际上不需要获取键的所有权,因此它应该只接收对其的不可变借用,这样xkey都是&T类型,因此我们可以对它们应用==

2
,你没有 find_and_remove 方法中的 VecCircle 的所有权。你只需要知道函数定义中的内容即可:
impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn find_and_remove(&self, key: T) -> Option<T>
}

这意味着您正在借用对 VecCircle 的引用。更长的写法是: borrowing a reference to VecCircle
fn find_and_remove(self: &VecCircle, key: T) -> Option<T>

也许这更明显?

由于您没有self的所有权,因此您也不能拥有self.0的所有权。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接