为什么将函数移至默认特征方法会导致借入错误?

问题描述 投票:1回答:2

给出包含元素集合的结构Foo

#[derive(Debug)]
struct Foo {
    bar: Vec<i8>,
}

我写了一个可变的视图对象,打算封装Foo的一部分:

#[derive(Debug)]
struct View<'a> {
    foo: &'a mut Foo,
}

impl<'a> View<'a> {
    fn iter(&'a self) -> std::slice::Iter<'a, i8> {
        self.foo.bar.iter()
    }

    fn iter_mut(&'a mut self) -> std::slice::IterMut<'a, i8> {
        self.foo.bar.iter_mut()
    }

    fn mutate(&'a mut self) {
        let mut vector: Vec<i8> = vec![];
        for value in self.iter().take(1).cloned() {
            vector.push(value);
        }
        for value in self.iter_mut() {
            *value = 0;
        }
    }
}

上面的View结构按预期工作,并且以下代码打印Foo { bar: [0, 0, 0] }

fn main() {
    let mut foo = Foo { bar: vec![0, 1, 2] };
    let mut view = View { foo: &mut foo };
    view.mutate();
    println!("{:?}", foo);
}

但是,不同类型的视图应该可以—如果Foo是矩阵,则视图可以是行,列甚至子矩阵。因此,我将View重写为由结构体实现的特征,并为mutate提供了默认实现:

trait AbstractView<'a> {
    type Iterator: Iterator<Item = &'a i8>;
    type IteratorMut: Iterator<Item = &'a mut i8>;

    fn iter(&'a self) -> Self::Iterator;
    fn iter_mut(&'a mut self) -> Self::IteratorMut;

    fn mutate(&'a mut self) {
        let mut vector: Vec<i8> = vec![];
        for value in self.iter().take(1).cloned() {
            vector.push(value);
        }
        for value in self.iter_mut() {
            *value = vector[0];
        }
    }
}

#[derive(Debug)]
struct View<'a> {
    foo: &'a mut Foo,
}

impl<'a> AbstractView<'a> for View<'a> {
    type Iterator = std::slice::Iter<'a, i8>;
    type IteratorMut = std::slice::IterMut<'a, i8>;

    fn iter(&'a self) -> Self::Iterator {
        self.foo.bar.iter()
    }

    fn iter_mut(&'a mut self) -> Self::IteratorMut {
        self.foo.bar.iter_mut()
    }
}

此代码无法成功编译,rustc抱怨iter_mut中对mutate的调用:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:18:22
   |
6  | trait AbstractView<'a> {
   |                    -- lifetime `'a` defined here
...
15 |         for value in self.iter().take(1).cloned() {
   |                      -----------
   |                      |
   |                      immutable borrow occurs here
   |                      argument requires that `*self` is borrowed for `'a`
...
18 |         for value in self.iter_mut() {
   |                      ^^^^^^^^^^^^^^^ mutable borrow occurs here

为什么将mutate实现为特征的默认方法会导致看起来与借阅检查器不同的行为?我怎样才能使这种特质发挥作用?

Example without the trait.

Example with the trait.

使用rustc版本1.43.1。

rust traits lifetime borrow-checker
2个回答
1
投票

很容易说出为什么基于特征的版本不起作用,但是很难说出原始的[[does


0
投票
由于SCappella's answer,我已经理解并解决了我的问题。因为我宁愿有一个干净的代码库,而不是一个用例有效的代码库,所以我用矢量替换了迭代器:
© www.soinside.com 2019 - 2024. All rights reserved.