MST

星途 面试题库

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

假设有一个结构体`Person`包含`name`和`age`字段,在一个函数中,你需要先不可变借用`Person`实例来读取`name`,然后可变借用它来修改`age`。但Rust的借用规则通常不允许这样做(先不可变借用再可变借用),请描述如何通过合理的设计(如使用`Cell`或`RefCell`)来实现这个需求,并解释原理。
33.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 使用RefCell实现
    • 代码示例
use std::cell::RefCell;

struct Person {
    name: String,
    age: u32,
}

fn modify_person(person: &RefCell<Person>) {
    // 不可变借用读取name
    let name = person.borrow().name.clone();
    println!("Name: {}", name);

    // 可变借用修改age
    let mut person_mut = person.borrow_mut();
    person_mut.age += 1;
}

fn main() {
    let person = RefCell::new(Person {
        name: "Alice".to_string(),
        age: 30,
    });
    modify_person(&person);
    println!("Age after modification: {}", person.borrow().age);
}
  • 原理
    • RefCell允许在运行时进行借用检查,而不是编译时。
    • borrow方法获取不可变借用,borrow_mut方法获取可变借用。在运行时,RefCell会跟踪当前是否有不可变或可变借用正在使用。如果违反借用规则(如在有不可变借用时尝试获取可变借用),会在运行时panic。但只要程序逻辑正确,就可以实现在同一作用域内先不可变借用再可变借用的操作。
  1. 使用Cell实现(如果nameCopy类型)
    • 代码示例
use std::cell::Cell;

struct Person {
    name: char, // 假设name是Copy类型,这里用char举例
    age: Cell<u32>,
}

fn modify_person(person: &Person) {
    // 读取name
    let name = person.name;
    println!("Name: {}", name);

    // 修改age
    person.age.set(person.age.get() + 1);
}

fn main() {
    let person = Person {
        name: 'A',
        age: Cell::new(30),
    };
    modify_person(&person);
    println!("Age after modification: {}", person.age.get());
}
  • 原理
    • Cell适用于内部类型实现了Copy trait的情况。
    • Cell提供getset方法来读取和修改内部值。它通过内部可变性,允许在不可变引用的情况下修改内部值。因为内部类型是Copy的,所以读取值时不会产生借用,也就不存在借用冲突问题,从而可以实现先读取再修改的操作。