MST
星途 面试题库

面试题:Rust切片在不同生命周期下的内存布局变化

假设你有一个函数接受不同生命周期的切片参数,分析在这些不同生命周期情况下,切片的内存布局会发生怎样的变化?并说明Rust编译器是如何确保内存安全的。给出具体代码示例进行解释。
13.2万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

切片的内存布局与生命周期分析

  1. 切片的内存布局
    • 在Rust中,切片 &[T] 本质上是一个胖指针,它包含两部分:指向切片数据起始位置的指针和切片的长度。无论切片的生命周期如何,其内存布局都是如此。例如,对于 &'a [i32],它有一个指向 i32 数组起始位置的指针和表示数组中 i32 数量的长度。
  2. 不同生命周期情况下的变化
    • 生命周期主要影响切片对数据的借用时长。不同生命周期的切片只是在作用域上有区别,其内存布局本身不会因为生命周期的不同而改变。例如,一个短生命周期的切片 &'short [T] 和一个长生命周期的切片 &'long [T],它们指向的数据如果相同,那么内存布局(指针 + 长度)是一样的,只是 &'short [T] 只能在 'short 这个较短的作用域内有效使用。
  3. Rust编译器确保内存安全的方式
    • Rust编译器通过生命周期检查来确保内存安全。它会检查所有借用关系,确保在任何时候都不会出现悬空指针(dangling pointer)。例如,不会出现一个切片在其指向的数据已经被释放后还被使用的情况。编译器会根据生命周期标注和作用域规则,拒绝那些可能导致内存不安全的代码。

代码示例

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    {
        // 短生命周期切片
        let short_slice: &[i32] = &numbers[0..3];
        println!("Short slice: {:?}", short_slice);
    }
    // 这里short_slice已经超出作用域,不能再使用
    // 长生命周期切片
    let long_slice: &[i32] = &numbers[2..5];
    println!("Long slice: {:?}", long_slice);
}

在这个示例中,short_slice 有一个较短的生命周期,局限于内层花括号内的作用域。long_slice 有一个较长的生命周期,能在其定义后的更大作用域内使用。编译器会确保 short_slice 不会在超出其作用域后被使用,从而保证内存安全。同时,两个切片的内存布局都是胖指针(指向 i32 数组起始位置的指针 + 长度)。