面试题答案
一键面试栈内存分配情况
- 简单数据类型:在Rust中,像整数(如
i32
、u8
等)、浮点数(f32
、f64
)、布尔值(bool
)、字符(char
)以及元组(tuple),只要其所有元素都是固定大小类型,这些简单数据类型在声明时通常分配在栈上。例如:
let num: i32 = 42;
let flag: bool = true;
let point: (i32, i32) = (10, 20);
这里的 num
、flag
和 point
都在栈上分配内存,因为它们的大小在编译时是已知的。
- 函数参数和局部变量:函数参数和在函数内部声明的局部变量,如果它们是简单数据类型或者固定大小的复合类型,也是在栈上分配。例如:
fn add_numbers(a: i32, b: i32) -> i32 {
let sum = a + b;
sum
}
这里的 a
、b
和 sum
都在栈上分配内存。
堆内存分配情况
- 复杂自定义结构体类型:如果自定义结构体包含动态大小的类型(如
String
、Vec<T>
等),那么整个结构体实例会在堆上分配。例如:
struct Person {
name: String,
age: i32,
}
let person = Person {
name: String::from("Alice"),
age: 30,
};
这里的 person
实例会在堆上分配,因为 name
字段是 String
类型,其大小在编译时不确定,需要在运行时根据字符串内容分配内存。
- 使用
Box<T>
等智能指针:当使用Box<T>
来包装类型时,被包装的类型会在堆上分配。例如:
let boxed_num = Box::new(42);
这里的 42
原本是栈上分配的 i32
类型,但通过 Box::new
包装后,boxed_num
指向堆上分配的 i32
数据。这种方式常用于需要在堆上分配单个值,并且希望在栈上有一个指向堆数据的句柄的场景。
- 动态大小类型(DST):Rust中的动态大小类型,如
str
(字符串切片,与String
不同)和 trait 对象,总是在堆上分配。例如:
let s: &str = "hello";
虽然 s
本身是栈上的引用,但它指向的字符串数据 "hello"
存储在静态存储区(类似堆的概念,在程序加载时分配)。当使用 String
时,它是 str
的拥有者类型,在堆上分配内存来存储字符串内容:
let string = String::from("world");
这里的 string
实例在堆上分配内存来存储字符串 "world"
。