面试题答案
一键面试- 移动语义和内存管理分析:
- 首先,
fn process_outer(outer: Outer)
函数通过值传递接收outer
变量。这意味着outer
的所有权被转移到函数内部。 let Inner { value } = outer.inner;
这一行代码从outer
中取出inner
结构体,并解构出value
字段。此时,outer.inner
的所有权被转移到value
变量(严格来说是Inner
结构体的成员被逐一移动到新的绑定中),outer
中的inner
字段现在处于 “已移动” 状态,不能再被使用。
- 首先,
- 创建新的
Outer
结构体:Outer { inner: Inner { value: value + 1 }, other_data: outer.other_data }
:- 新的
Inner
结构体创建:Inner { value: value + 1 }
创建了一个新的Inner
结构体实例,其value
字段是原value
加1。这里新的Inner
结构体在栈上分配内存(因为Inner
是一个简单的结构体,其成员value
是i32
,是一个固定大小的类型)。 other_data: outer.other_data
:outer.other_data
的所有权被转移到新创建的Outer
结构体中。Vec<String>
类型的数据存储在堆上,通过所有权转移,新的Outer
结构体现在负责管理这块堆内存。
- 新的
- 函数返回新创建的
Outer
结构体,其所有权被转移出函数,调用者现在拥有这个新的Outer
结构体实例,并负责管理其内存。当调用者的作用域结束时,Outer
结构体的析构函数会被调用,它会首先调用other_data
成员(Vec<String>
)的析构函数来释放堆上的字符串数据,然后Inner
结构体的析构函数会被调用(由于Inner
只有简单类型i32
,其析构函数为空操作),从而完成整个内存管理过程。
代码实现如下:
struct Inner {
value: i32
}
struct Outer {
inner: Inner,
other_data: Vec<String>
}
fn process_outer(outer: Outer) -> Outer {
let Inner { value } = outer.inner;
Outer {
inner: Inner {
value: value + 1
},
other_data: outer.other_data
}
}
这样,代码通过移动语义和正确的内存管理,创建了一个新的 Outer
结构体,其中 Inner
结构体的 value
字段增加了1。