面试题答案
一键面试- 栈内存和堆内存分配
- 栈内存:
- 对于结构体中所有基础类型(如
i32
、bool
等)的成员,它们会直接存储在栈上。例如,如果结构体有一个i32
类型的成员num
,num
的值会直接存储在栈上结构体实例的内存空间内。 - 对于
Vec<T>
类型的成员,Vec
本身是一个胖指针(fat pointer),它由三个部分组成:指向堆上数据的指针、长度和容量。这三个部分会存储在栈上,而实际存储T
类型元素的数据块会在堆上分配。 - 对于自定义结构体类型的成员,如果这个自定义结构体只包含基础类型成员,那么整个自定义结构体实例会像基础类型一样存储在栈上。例如,如果有一个自定义结构体
Inner { field: i32 }
,并且外部结构体包含Inner
类型的成员,Inner
实例会直接存储在栈上外部结构体实例的内存空间内。
- 对于结构体中所有基础类型(如
- 堆内存:
Vec<T>
类型成员实际存储元素的数据块在堆上分配。例如,Vec<i32>
会在堆上分配一块连续的内存来存储i32
元素。如果Vec
的长度为n
,会在堆上分配n * size_of::<i32>()
大小的内存空间。- 如果自定义结构体成员包含
Vec<T>
或其他需要堆分配的数据结构,那么这些部分会在堆上分配。例如,自定义结构体Inner { vec: Vec<i32> }
,vec
中的数据会在堆上分配,尽管Inner
结构体实例可能存储在栈上(如果外部结构体在栈上创建)。
- 栈内存:
- 所有权和生命周期对内存分配的影响
- 所有权:
- 当创建结构体实例时,结构体获得其成员的所有权。例如,对于
Vec<T>
成员,在Vec
创建时就拥有了堆上存储元素数据块的所有权。如果将结构体实例赋值给另一个变量,整个结构体(包括其成员的所有权)会转移。例如:
- 当创建结构体实例时,结构体获得其成员的所有权。例如,对于
- 所有权:
struct MyStruct {
vec: Vec<i32>,
}
let s1 = MyStruct { vec: vec![1, 2, 3] };
let s2 = s1; // s1不再拥有vec的所有权,所有权转移到s2
- 对于自定义结构体成员,如果其内部有拥有所有权的数据结构(如`Vec`),那么外部结构体拥有整个自定义结构体成员的所有权,包括内部数据结构的所有权。
- 生命周期:
- 结构体的生命周期至少要与其所有成员的生命周期一样长。例如,如果结构体有一个
Vec<T>
成员,Vec
的生命周期不能超过结构体的生命周期。如果Vec
在结构体之前被销毁,会导致悬空指针错误。 - 对于包含自定义结构体成员的情况,如果自定义结构体有生命周期参数,外部结构体的生命周期需要考虑内部自定义结构体的生命周期。例如:
- 结构体的生命周期至少要与其所有成员的生命周期一样长。例如,如果结构体有一个
struct Inner<'a> {
data: &'a i32,
}
struct Outer<'a> {
inner: Inner<'a>,
}
let num = 42;
let inner = Inner { data: &num };
let outer = Outer { inner };
这里Outer
结构体的生命周期依赖于Inner
结构体,而Inner
结构体的生命周期依赖于&'a i32
引用的生命周期。Outer
结构体的实例outer
的生命周期不能超过num
的生命周期,因为Inner
中的引用指向num
。当num
被销毁时,outer
也不能再安全使用。