You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust所有权转移时的内存变化机制及相关疑问

Rust所有权转移与内存变化解析

一、所有权转移时的栈内存变化

当一个值的所有权从变量A转移到变量B(即发生move操作)时,对于栈分配的类型(比如示例中的Test结构体,仅包含栈上存储的u8),实际逻辑是:

  • 值的字节数据会从A所在的栈位置,直接复制到B的栈位置;
  • 原变量A会被标记为无效,后续无法再被使用;
  • 当A所在的作用域结束时,因为A已经不再拥有任何值的所有权,所以不会触发Drop trait的drop方法,其对应的栈内存会被栈帧回收,但此时这块内存里的有效数据已经转移到B的位置,不会影响B的使用。

二、第一个示例:内部块变量转移所有权后的内存逻辑

看这段代码:

struct Test(u8);

impl Drop for Test {
   fn drop(&mut self) {
      println!("{} is dropped", self.0);
  }
}

fn main() {
   let test;
   {
       println!("step 1");
       let t = Test(1);
       println!("step 2");
       test = t;
   } 
   println!("{}", test.0);
}

输出:

step 1
step 2
1
1 is dropped

关键细节:

  1. Test(1)是栈分配实例,最初存储在内部块的栈帧中(变量t的位置);
  2. 执行test = t时发生所有权转移:t的字节数据(即u8值1)被移动到main函数中test的栈位置;
  3. 内部块结束时,变量t已失去所有权,不会调用drop;
  4. 内部块的栈帧会被正常回收,但t对应的位置已无有效所有权数据,所以不会影响test;
  5. 直到main函数结束,test作为最终所有者才会触发drop,因此最后打印1 is dropped。

三、第二个示例:函数返回值的所有权处理

对于函数返回值的场景,Rust编译器会通过**返回值优化(RVO)**避免不必要的内存移动:

fn main() {
   println!("step 1");
   let test = create_struct();
   println!("step 2");
   println!("{}", test.0);
}

pub fn create_struct() -> Test {
   Test(1)
}

输出:

step 1 
step 2 
1 
1 is dropped 
  • 编译器不会在create_struct的栈帧里创建Test(1)实例再移动到main的test位置,而是直接在main函数中test的栈位置创建这个实例;
  • 即使没有开启RVO,Rust也会把函数内的实例所有权转移给调用者的变量,此时函数内的临时变量因失去所有权,在函数结束时不会触发drop,实例不会被回收;
  • 最终test作为所有者,在main结束时触发drop,符合输出结果。

四、为什么只有一次drop?

因为Test实现了Drop trait,Rust会自动为其移除Copy trait(一个类型不能同时实现Copy和Drop),所以所有操作都是所有权转移而非复制。整个过程中始终只有一个Test实例,只是所有权在不同变量间转移,只有当最终的所有者(main里的test)超出作用域时,才会调用一次drop。

内容的提问来源于stack exchange,提问作者kyles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:14:52