wxvirus wxvirus
首页
  • Go文章

    • Go语言学习
  • Rust

    • Rust学习
  • Java

    • 《Java》
  • Python文章

    • Python
  • PHP文章

    • PHP设计模式
  • 学习笔记

    • 《Git》
  • HTML
  • CSS
  • JS
  • 技术文档
  • GitHub技巧
  • 刷题
  • 博客搭建
  • 算法学习
  • 架构设计
  • 设计模式
  • 学习
  • 面试
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

无解的lifecycle

let today = new Beginning()
首页
  • Go文章

    • Go语言学习
  • Rust

    • Rust学习
  • Java

    • 《Java》
  • Python文章

    • Python
  • PHP文章

    • PHP设计模式
  • 学习笔记

    • 《Git》
  • HTML
  • CSS
  • JS
  • 技术文档
  • GitHub技巧
  • 刷题
  • 博客搭建
  • 算法学习
  • 架构设计
  • 设计模式
  • 学习
  • 面试
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • C&C++

  • PHP

  • Python

  • Go

  • microservice

  • rust

    • windows安装和配置
    • rust的第一个程序
    • cargo
    • 变量和基本类型
    • 函数和模块
    • 函数参数传递
    • 表达式和语句以及判断
    • 字符串练习
    • 自定义函数和模块的使用
    • 结构体入门和基本写法
    • trait入门
    • 生命周期
    • Vector快速入门
    • 所有权以及所有权转移
      • 基本口诀
      • 案例
        • 实现 Clone 以及自动默认值
    • 宏入门
    • 在struct中使用泛型
  • Java

  • 学习笔记

  • 后端
  • rust
wxvirus
2022-12-08

所有权以及所有权转移

# 所有权以及所有权转移

let a = xxx;

xxx是值,对应的变量是a,那么a就是xxx(值)的所有者。

# 基本口诀

  • 值在任意时刻有且只有一个所有者
  • 当所有者离开作用域,这个值将被销毁

# 案例

let a = String::from("a");
let b = a; // 所有者转移
println!("a: {}", a);
1
2
3

这里字符串的所有者发生了转移,到了最后一步,就会报错。

变量a原本是指向一个字符串a,此时再讲所有者转移给了b,此时a就跟未初始化的变量一样,是不能进行打印的。

文档:https://doc.rust-lang.org/std/marker/trait.Copy.html (opens new window)

为什么使用i32类型的就可以编译通过且不报错,i32类型已经实现了Copy这个trait方法。

  1. Copy和Move很类似,拷贝后,并不会销毁原变量
  2. 一个类型所有属性都实现了Copy,那么它本身就可以实现Copy
  3. 常见数字类型、bool类型都已经实现了Copy
  4. 凡是实现Drop trait的不能再实现Copy【String就是】
  5. Copy好比是一个浅拷贝,Clone实现了深拷贝
  6. Copy告诉编译器这个类型默认采用copy语义,而不是move语义【clone是面向程序员的,是需要自己来实现的】

自定义一个结构体

struct User {
    id: i32,
}

fn main() {

    let a = User { id: 123 };
    let b = a;
    println!("a: {}, b: {}", a, b);
}
1
2
3
4
5
6
7
8
9
10

上面这样是会报错的,我们可以使用#[derive]来自动实现,可以加一个Debug以及Clone和Copy,通常这 2 个是一起的

#[derive(Debug, Clone, Copy)]
struct User {
    id: i32,
}

fn main() {

    let a = User { id: 123 };
    let b = a;
    println!("a: {:?}, b: {:?}", a, b);
}
1
2
3
4
5
6
7
8
9
10
11

这个过程不会把a给“废掉”,还可以继续使用。


我们也可以自己实现Copy

#[derive(Debug)]
struct User {
    id: i32,
}

impl Copy for User {} // 这是空的impl 这是面向编译器的,告诉编译器这个情况不使用 move 语义,使用 copy 语义

impl Clone for User {
    // 抄的文档里的代码 官方搞的示例
    fn clone(&self) -> Self {
        *self
    }
}

fn main() {
    let a = User { id: 123 };
    let b = a;
    println!("a: {:?}, b: {:?}", a, b);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

一般还是采用#[derive(Debug, Clone, Copy)]比较方便。


此时:我们在User结构体里加一个String类型的name,就应证了 上面的第四点 ,String是没法被Copy的

# 实现 Clone 以及自动默认值

#[derive(Debug, Default)]
struct User {
    id: i32,
    name: String,
    age: i32,
}

impl Clone for User {
    fn clone(&self) -> Self {
        User {
            id: self.id, // i32 实现了 Copy 可以直接写
            name: self.name.clone() + "被克隆", // 没有实现就得加上 .clone() 方法
            age: self.age, // i32 直接使用
        }
    }
}

fn main() {
    let a = User {
        id: 123,
        ..Default::default()
    };
    let b = a.clone();
    println!("a: {:?}, b: {:?}", a, b);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

加上Default,下面实例化结构体的时候可以使用..Default::default()来给对应的字段赋初值。

运行:

cargo build && cargo run
warning: `mypro` (bin "mypro") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/mypro`
a: User { id: 123, name: "", age: 0 }, b: User { id: 123, name: "被克隆", age: 0 }
1
2
3
4
5
编辑 (opens new window)
#owner
上次更新: 2022/12/08, 22:08:26
Vector快速入门
宏入门

← Vector快速入门 宏入门→

最近更新
01
vue3配合vite初始化项目的一些配置
07-26
02
网盘系统开发学习
07-24
03
linux多进程
06-19
更多文章>
Theme by Vdoing | Copyright © 2021-2024 wxvirus 苏ICP备2021007210号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式