Rust匹配和借用检查器

时间:2017-08-04 11:25:32

标签: rust matching borrow-checker

我一直磕磕绊绊地看着我的Rust程序中的模式,这种模式总是让我与借用检查器发生冲突。请考虑以下玩具示例:

use std::sync::{Arc,RwLock};

pub struct Test {
    thing: i32,
}

pub struct Test2 {
    pub test: Arc<RwLock<Test>>,
    pub those: i32,
}

impl Test {
    pub fn foo(&self) -> Option<i32> {
        Some(3)
    }
}

impl Test2 {
    pub fn bar(&mut self) {
        let mut test_writer = self.test.write().unwrap();

        match test_writer.foo() {
            Some(thing) => {
                self.add(thing);
            },
            None => {}
        }
    }

    pub fn add(&mut self, addme: i32) {
        self.those += addme;
    }
}

这不会编译,因为add中的Some函数试图可变地借用自己,这已经在match语句之上不可靠地借用以打开读写锁。

我在Rust中遇到过这种模式几次,主要是在使用RwLock时。我还找到了一种解决方法,即在match语句之前引入一个布尔值,然后在Some臂中更改布尔值,然后最后在此布尔值后引入一个测试匹配语句,以便在Some手臂上做我想做的任何事情。

在我看来,这不是解决问题的方法,我认为在Rust中这样做更为惯用的方式 - 或以完全不同的方式解决问题 - 但我找不到它。如果我没有弄错,问题与词汇借用有关,所以self不能在匹配声明的范围内可变地借用。

是否有一种惯用的Rust方式来解决这类问题?

2 个答案:

答案 0 :(得分:2)

Use directly the field those, for example with custom type:

use std::sync::{Arc,RwLock};

pub struct Those(i32);

impl Those {
    fn get(&self) -> i32 {
        self.0
    }

    fn add(&mut self, n: i32) {
        self.0 += n;
    }
}

pub struct Test {
    thing: Those,
}

pub struct Test2 {
    pub test: Arc<RwLock<Test>>,
    pub those: Those,
}

impl Test {
    pub fn foo(&self) -> Option<Those> {
        Some(Those(3))
    }
}

impl Test2 {
    pub fn bar(&mut self) {
        let mut test_writer = self.test.write().unwrap();

        match test_writer.foo() {
            Some(thing) => {
                // call a method add directly on your type to get around the borrow checker
                self.those.add(thing.get());
            },
            None => {}
        }
    }
}

答案 1 :(得分:1)

You either need to end borrow of a part of self, before mutating self

pub fn bar1(&mut self) {
    let foo = self.test.write().unwrap().foo();
    match foo {
        Some(thing) => {
            self.add(thing);
        },
        None => {}
    }
}

or directly mutate non borrowed part of self

pub fn bar2(&mut self) {
    let test_writer = self.test.write().unwrap();

    match test_writer.foo() {
        Some(thing) => {
            self.those += thing;
        },
        None => {}
    }
}