什么是关于可变内部引用的Rust借用规则?

时间:2017-01-14 00:20:17

标签: rust

对我来说,为什么像

这样的程序并不直观
#[derive(Debug)]
struct Test {
    buf: [u8; 16],
}

impl Test {
    fn new() -> Test {
        Test {
            buf: [0u8; 16],
        }       
    }   

    fn hi(&mut self) {
        self.buf[0] = 'H' as u8; 
        self.buf[1] = 'i' as u8; 
        self.buf[2] = '!' as u8; 
        self.print();
    }   

    fn print(&self) {
        println!("{:?}", self);
    }   
}

fn main() {
    Test::new().hi();
}

编译并运行没有任何问题,但是像

这样的程序
#[derive(Debug)]
enum State {
    Testing([u8; 16]),
}

#[derive(Debug)]
struct Test {
    state: State,
}       

impl Test {
    fn new() -> Test {
        Test {
            state: State::Testing([0u8; 16]),
        }
    }   

    fn hi(&mut self) {
        match self.state {
            State::Testing(ref mut buf) => {
                buf[0] = 'H' as u8;
                buf[1] = 'i' as u8;
                buf[2] = '!' as u8;
                self.print();
            },
        }
    }

    fn print(&self) {
        println!("{:?}", self);
    }
}

fn main() {
    Test::new().hi();
}
编译时出现

错误

  

错误[E0502]:无法将*self借用为不可变因为   self.state.0也被借用为可变

由于两个程序基本上都是相同的东西,第二个似乎从内存的角度看起来不太安全。我知道必须有一些关于我必须缺少的借用和范围规则,但不知道是什么。

2 个答案:

答案 0 :(得分:3)

为了使hi函数正常工作,您只需将print移出其match表达式中引入的可变扩展的范围:

fn hi(&mut self) {
    match self.state {
        State::Testing(ref mut buf) => {
            buf[0] = 'H' as u8;
            buf[1] = 'i' as u8;
            buf[2] = '!' as u8;
        },
    }
    self.print();
}

由于第二种情况中存在match块,您的两个变体不相等。我不知道如何在没有模式匹配的情况下直接访问enum中的元组结构(或者如果现在甚至可能这样),但如果是这样的话,那么实际上并不多差异和两个版本都可以。

答案 1 :(得分:2)

match声明中,您借用self.state。借用范围是词法,因此它在整个match块中借用。致电self.print()时,您需要借用self。但这是不可能的,因为self的一部分已经被借用了。如果您在self.print()语句后移动match,则会有效。

关于词汇借阅范围,您可以在Two bugs in the borrow checker every Rust developer should know about的第二部分阅读更多内容。相关问题:#6393#811