MST

星途 面试题库

面试题:Rust结构体可变性与借用规则的交互

假设有一个结构体`Person`,包含`name`和`age`字段。写一段代码,在一个函数中,同时获取结构体实例的可变引用和不可变引用,并解释为什么这样做可能会导致编译错误,以及如何修改代码以避免错误。
40.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let mut person = Person {
        name: String::from("Alice"),
        age: 30,
    };

    // 获取不可变引用
    let name_ref = &person.name;

    // 获取可变引用前需要先释放不可变引用
    // 这里注释掉下面获取可变引用的代码会导致编译错误,因为在同一作用域内不能同时存在不可变和可变引用
    // let age_mut_ref = &mut person.age;

    // 为了避免错误,可以先使用完不可变引用,再获取可变引用
    drop(name_ref);
    let age_mut_ref = &mut person.age;
    *age_mut_ref = 31;
}

编译错误原因

Rust的借用规则规定,在同一作用域内,不能同时存在对同一数据的可变引用和不可变引用。这是为了防止数据竞争(data race),因为可变引用允许修改数据,而不可变引用允许读取数据,如果两者同时存在,可能会导致读取到不一致的数据。

修改方式

  1. 先后获取引用:先使用完不可变引用,再获取可变引用。如上述代码中,通过drop(name_ref)手动释放不可变引用,然后再获取可变引用。
  2. 分离作用域:将不可变引用和可变引用的使用放在不同的作用域内,这样在同一时刻只有一种引用存在。例如:
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let mut person = Person {
        name: String::from("Alice"),
        age: 30,
    };
    {
        let name_ref = &person.name;
        // 使用name_ref
    }
    let age_mut_ref = &mut person.age;
    *age_mut_ref = 31;
}

这里不可变引用name_ref的作用域被限制在花括号内,当离开这个作用域时,name_ref被释放,此时可以安全地获取可变引用age_mut_ref