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

为何这段Rust代码违背所有权规则却能正常运行?

关于Rust所有权的疑问:为何转移所有权后原变量仍可使用?

以下是我编写的Rust代码:

use euclid::Vector3D;

fn main() {
    fn add_vectors<Unit>(a: Vector3D<f64, Unit>, b: Vector3D<f64, Unit>) -> Vector3D<f64, Unit> {
        // 我获取了`a`和`b`的所有权。
        Vector3D::<f64, Unit>::new(a.x + b.x, a.y + b.y, a.z + b.z) // 显式创建新向量并返回其所有权。
    } // `a`和`b`超出作用域,被销毁。
    enum Meters {}
    let v1 = Vector3D::<f64, Meters>::new(1., 2., 3.);
    let v2 = Vector3D::<f64, Meters>::new(1., 2., 3.);
    // 至此,`main`是`v1`和`v2`的所有者。
    println!("Added: {:?}", add_vectors(v1, v2)); // 所有权转移至`add_vectors`。
    println!("Original vectors: {:?} and {:?}", v1, v2); // 此时`v1`和`v2`应已被销毁。
}

这段代码无警告编译并运行,这在Python中是正常的,但这是Rust。根据《Rust编程圣经》中所有权的知识,我认为第二个println!不应能使用v1和v2,我的推理如下:

  • add_vectors接收向量本身而非引用,因此获取了它们的所有权。
  • 在add_vectors函数体中,显式创建了新的Vector3D::<f64, Unit>并返回。
  • 当add_vectors执行完毕,a和b超出作用域被销毁。
  • 此时v1和v2应已不存在。

(我正在学习Rust,若答案过于浅显还请见谅。)


问题原因解析

核心原因是euclid::Vector3D在此场景下实现了Copy trait,导致参数传递时是复制而非所有权转移:

  1. Copy trait的作用:Rust中实现Copy的类型,在值传递时会自动复制一份新的实例,原变量的所有权不会转移,仍然可以正常使用。基本数据类型(如f64、i32)和由Copy类型组成的结构体/枚举,只要没有包含非Copy字段,就会自动推导实现Copy。
  2. Vector3D的Copy推导:你定义的Vector3D<f64, Meters>中,f64是Copy类型,Meters是空枚举(空枚举默认实现Copy),因此整个Vector3D结构体满足Copy的条件,被自动实现了该trait。
  3. 函数调用的实际行为:当你调用add_vectors(v1, v2)时,Rust会自动复制v1和v2,将副本传递给函数参数a和b,原变量v1和v2的所有权仍属于main函数,所以在后续的println!中可以正常访问。

验证方法

如果想验证所有权转移的逻辑,可以修改代码让Vector3D不满足Copy条件:

use euclid::Vector3D;

fn main() {
    fn add_vectors<Unit>(a: Vector3D<f64, Unit>, b: Vector3D<f64, Unit>) -> Vector3D<f64, Unit> {
        Vector3D::<f64, Unit>::new(a.x + b.x, a.y + b.y, a.z + b.z)
    }
    // 定义一个包含非Copy类型的Unit
    enum Meters {
        Value(String),
    }
    let v1 = Vector3D::<f64, Meters>::new(1., 2., 3., Meters::Value("meter".to_string()));
    let v2 = Vector3D::<f64, Meters>::new(1., 2., 3., Meters::Value("meter".to_string()));
    println!("Added: {:?}", add_vectors(v1, v2));
    // 此时编译器会报错:use of moved value: `v1`
    println!("Original vectors: {:?} and {:?}", v1, v2);
}

此时编译器会提示你使用了已移动的变量,符合你最初对所有权转移的预期。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:41:32