Rust函数与所有权

发布于:2025-07-04 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、 标量和简单的堆分配类型

 // 函数与所有权
    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,传递时拷贝数据,不转移所有权。

  • 复杂类型如 StringVec 不实现 Copy,传递时会移动所有权,防止资源泄漏和悬挂指针。


如果需要,我可以帮你写出这两个函数的示例实现,或者扩展说明所有权与借用的更多细节。

二、自定义类型中栈分配类型和堆分配类型同时存在


🟢 如果你的 struct 里全是 标量类型(比如 i32boolf64 等),那么:

  • 当结构体作为参数传给函数时,它会 发生复制(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 中包含 堆分配类型(如 StringVec),就会发生 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 行为?