MST

星途 面试题库

面试题:Rust中所有权和借用的理解及应用

请解释Rust中所有权和借用的概念,并举例说明在实际代码中如何避免因所有权和借用规则导致的错误。
41.4万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

所有权概念

  1. 定义:Rust的所有权系统是其内存管理的核心机制。每个值在Rust中都有一个变量,称为该值的所有者。当所有者离开其作用域时,该值将被释放。
  2. 规则
    • 每个值都有一个唯一的所有者。
    • 当所有者离开作用域时,值被丢弃。
  3. 示例
fn main() {
    let s = String::from("hello"); // s 是 "hello" 的所有者
    // s 的作用域在此处结束,"hello" 会被释放
}

借用概念

  1. 定义:借用允许你在不获取所有权的情况下使用值。有两种类型的借用:不可变借用(&T)和可变借用(&mut T)。
  2. 规则
    • 同一时间,你可以有任意数量的不可变借用或一个可变借用。
    • 借用的作用域不能超过所有者的作用域。
  3. 示例
fn main() {
    let s = String::from("hello");
    let len = calculate_length(&s); // 不可变借用
    println!("The length of '{}' is {}.", s, len);

    let mut s1 = String::from("world");
    change(&mut s1); // 可变借用
    println!("s1 is now {}", s1);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

fn change(s: &mut String) {
    s.push_str(", world");
}

避免因所有权和借用规则导致错误的方法

  1. 理解作用域:确保借用的作用域合理,避免在借用的值超出其所有者作用域后仍使用借用。例如:
fn main() {
    let s;
    {
        let temp = String::from("test");
        s = &temp; // 错误,temp离开作用域后,s成为悬垂引用
    }
    // 使用 s 会导致未定义行为
}

正确做法是让所有者的作用域覆盖借用的使用:

fn main() {
    let temp = String::from("test");
    let s = &temp;
    println!("{}", s);
}
  1. 遵循借用规则:避免同时存在可变借用和不可变借用。例如:
fn main() {
    let mut data = String::from("rust");
    let r1 = &data; // 不可变借用
    let r2 = &mut data; // 错误,同一时间不能有不可变和可变借用
    println!("{} {}", r1, r2);
}

正确做法是先结束不可变借用,再进行可变借用:

fn main() {
    let mut data = String::from("rust");
    {
        let r1 = &data;
        println!("{}", r1);
    }
    let r2 = &mut data;
    r2.push_str(" rules");
    println!("{}", r2);
}
  1. 使用生命周期标注:在函数或结构体中使用泛型时,明确生命周期参数,确保借用的生命周期合理。例如:
struct Container<'a> {
    value: &'a i32
}

fn main() {
    let num = 42;
    let container = Container { value: &num };
    println!("{}", container.value);
}

通过'a生命周期标注,确保container中的借用value不会超过num的生命周期。