Rust函数与所有权
一、 标量和简单的堆分配类型
// 函数与所有权let s = String::from("hello");takes_ownership(s); // s的所有权被移动到函数中// println!("{}", s); // 这里会报错,因为s已经无效let x = 5;makes_copy(x); // x是Copy类型,不会被移动println!("{}", x); // x仍然有效
好的,下面帮你详细讲解这段代码涉及的 Rust 所有权和 Copy 特性:
// 函数与所有权示例
let s = String::from("hello");
takes_ownership(s); // s 的所有权被移动到函数中
// println!("{}", s); // 这里会报错,因为 s 已经无效let x = 5;
makes_copy(x); // x 是 Copy 类型,不会被移动
println!("{}", x); // x 仍然有效
1. 所有权和移动(Move)——关于 String
-
String
是一个拥有堆数据的复杂类型,它管理了堆上的内存。 -
当你写
takes_ownership(s)
时,变量s
的所有权被**移动(move)**到了函数takes_ownership
里。 -
移动后,原变量
s
不再有效,Rust 编译器防止你继续使用它,避免悬挂指针或重复释放。 -
因此,注释掉的
println!("{}", s);
会编译错误,提示变量s
已经失效。
2. Copy 语义——关于整数 i32
-
x = 5
是一个整数,属于 Rust 的标量类型,并且实现了Copy
trait。 -
这意味着当你调用
makes_copy(x)
时,变量x
的值会**被复制(copy)**传递给函数。 -
函数内部得到的是
x
的一个副本,原变量x
依然有效。 -
所以
println!("{}", x);
可以正常打印5
。
3. 总结对比:
类型 | 传参行为 | 是否可以继续使用原变量 | 示例 |
---|---|---|---|
String | 移动(move) | 不可以 | takes_ownership(s) |
i32 等标量 | 复制(copy) | 可以 | makes_copy(x) |
4. 额外说明:
-
标量类型(如整数、布尔值、浮点数)默认实现
Copy
,传递时拷贝数据,不转移所有权。 -
复杂类型如
String
、Vec
不实现Copy
,传递时会移动所有权,防止资源泄漏和悬挂指针。
如果需要,我可以帮你写出这两个函数的示例实现,或者扩展说明所有权与借用的更多细节。
二、自定义类型中栈分配类型和堆分配类型同时存在
🟢 如果你的 struct
里全是 标量类型(比如 i32
、bool
、f64
等),那么:
-
当结构体作为参数传给函数时,它会 发生复制(Copy),不是移动(Move);
-
函数调用之后,原变量仍然有效,可以继续使用;
-
因为这些标量类型本身就是实现了
Copy
trait,整个 struct 也会自动实现Copy
。
✅ 示例一:结构体里全是标量类型(自动 Copy)
#[derive(Debug)]
struct Point {x: i32,y: i32,
}fn print_point(p: Point) {println!("{:?}", p); // p 拷贝而非移动
}fn main() {let p1 = Point { x: 3, y: 4 };print_point(p1);println!("{:?}", p1); // ✅ 正常打印,p1 仍然有效
}
Point
自动实现了Copy
(因为它的成员都实现了 Copy),所以传参时是拷贝。
⚠️ 但如果 struct 中包含 堆分配类型(如 String
、Vec
),就会发生 Move(移动):
struct User {name: String,age: u32,
}fn take_user(u: User) {println!("{}", u.name);
}fn main() {let u1 = User {name: String::from("Alice"),age: 30,};take_user(u1);// println!("{}", u1.age); // ❌ 报错:u1 已被移动
}
✅ 总结:
情况 | 是否移动 | 是否还能使用原变量 |
---|---|---|
struct 全是标量 | ❌ Copy | ✅ 可以继续用 |
struct 含有堆分配类型(String 等) | ✅ Move | ❌ 无法再访问 |
如有需要,也可以 #[derive(Copy, Clone)]
强制实现 Copy
,前提是所有字段都必须是 Copy
的。
是否需要我帮你写一段 struct 混合字段(标量 + String)演示 move 行为?