简体   繁体   English

锈匹配和借阅检查器

[英]Rust matching and borrow checker

I keep stumbling on a pattern in my Rust programs that always puts me at odds with the borrow-checker. 我一直在我的Rust程序中绊脚石,这总是使我与借位检查器不一致。 Consider the following toy example: 考虑以下玩具示例:

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;
    }
}

This doesn't compile because the add function in the Some arm tries to borrow self mutably, which was already borrowed immutably just above the match statement in order to open the read-write lock. 这不会编译,因为Some分支中的add函数尝试以可变方式借用self,而在match语句上方已经以不可变的方式借用了self以打开读写锁。

I've encountered this pattern a few times in Rust, mainly when using RwLock . 我在Rust中几次遇到了这种模式,主要是在使用RwLock I've also found a workaround, namely by introducing a boolean before the match statement and then changing the value of the boolean in the Some arm and then finally introducing a test on this boolean after the match statement to do whatever it is I wanted to do in the Some arm. 我还找到了一种解决方法,即在match语句之前引入一个布尔值,然后在Some臂中更改布尔值,然后在match语句之后最终对该布尔值引入一个测试,以执行我想做的任何事情在Some手臂上做。

It just seems to me that that's not the way to go about it, I assume there's a more idiomatic way to do this in Rust - or solve the problem in an entirely different way - but I can't find it. 在我看来,这不是解决问题的方法,我认为在Rust中有一种更惯用的方法可以做到这一点-或以完全不同的方式解决问题-但我找不到。 If I'm not mistaken the problem has to do with lexical borrowing so self cannot be mutably borrowed within the arms of the match statement. 如果我没记错的话,问题就与词汇借用有关,因此self不能在match语句的范围内可变地借用。

Is there an idiomatic Rust way to solve this sort of problem? 有没有惯用的Rust方法来解决这类问题?

Use directly the field those , for example with custom type: 直接使用领域those ,例如自定义类型:

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 => {}
        }
    }
}

You either need to end borrow of a part of self , before mutating self 在变异self之前,您要么需要终止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 或直接突变的非借用部分self

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM