MST

星途 面试题库

面试题:Rust中数组与切片内存布局的差异

请阐述Rust中数组(Array)和切片(Slice)在内存布局上有哪些主要差异,并举例说明这种差异如何影响它们的使用场景。
46.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

内存布局差异

  1. 数组
    • 数组是固定大小的,其内存布局是在栈上连续分配的。例如,let arr: [i32; 5] = [1, 2, 3, 4, 5];,这5个i32类型的元素在栈上是紧密排列的,大小为5 * std::mem::size_of::<i32>()字节。数组的大小在编译时就确定,并且不能改变。
  2. 切片
    • 切片是动态大小的视图,它本身是一个胖指针(fat pointer),在64位系统上,切片的大小为16字节(8字节指向数据的指针,8字节表示切片长度)。切片并不拥有数据,而是借用其他数据结构(如数组或堆上分配的Vec)的数据。例如,let s: &[i32] = &arr[1..3];,切片s指向arr数组中的部分数据,切片本身的内存布局是在栈上,而实际的数据仍在arr所在的内存位置。

对使用场景的影响

  1. 数组
    • 固定大小场景:当需要一个固定大小的数据集合,并且希望在栈上分配内存以提高性能和简单性时,使用数组。比如一个游戏中固定数量的玩家位置数组,每个玩家的位置可以是一个(i32, i32)的元组,由于玩家数量在游戏设计时就确定,使用数组很合适。
    let player_positions: [(i32, i32); 10] = [(0, 0); 10];
    
  2. 切片
    • 动态大小或借用场景:当需要处理动态大小的数据块或者需要借用其他数据结构的数据时,使用切片。例如,在读取文件内容时,不知道文件具体大小,读取的数据可以用&[u8]切片来处理。
    use std::fs::File;
    use std::io::{Read, Seek, SeekFrom};
    
    let mut file = File::open("example.txt").expect("Failed to open file");
    let file_size = file.seek(SeekFrom::End(0)).expect("Failed to seek");
    file.seek(SeekFrom::Start(0)).expect("Failed to seek");
    let mut buffer = vec![0; file_size as usize];
    file.read(&mut buffer).expect("Failed to read");
    let slice: &[u8] = &buffer;
    
    • 切片在函数参数传递中也很常用,因为它允许函数处理不同大小的数据块,而不需要关心具体的数据所有者,提高了代码的通用性。例如:
    fn process_slice(slice: &[i32]) {
        for num in slice {
            println!("{}", num);
        }
    }
    
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    process_slice(&arr);
    let vec: Vec<i32> = vec![6, 7, 8];
    process_slice(&vec);