【Rust 中级教程】 10 所有权(3)
0x00 开篇
上一篇文章介绍了所有权在变量间赋值的转移操作,以及详细对比了与其它语言的异同。本篇文章将继续介绍另外两种转移操作——向函数传递值和从函数返回值。本篇文章的阅读时间大约 8 分钟。
0x01 转移——向函数传递值
先上代码:
fn main() {
let name = String::from("ZhangSan");
print_name(name);
println!("{}", name);
}
fn print_name(name: String) {
println!("My name is {}", name);
}
如果用目前大部分的主流代码的思想去看上面的代码,都会认为没有问题。但是在 Rust 中,它则会编译失败。
失败的错误与上一篇文章介绍的变量赋值一样。当我们把外部的变量传递到函数内部时,外部变量的所有权将会转移到函数内部。此时,外部将无法再次使用该变量了。j简易示意过程如下:
向函数传值所有权转移 简易示意图
代码释义:
fn main() {
// 1. 创建 name,name所有权在 main 函数作用域内
let name = String::from("ZhangSan");
// 2.
// 2.1 将 name 以参数形式传递到 print_name 函数中
// 2.2 name 离开 main 函数作用域,所有权转移到函数内部
print_name(name);
// 5.接下来 将无法再使用 name 变量
// name 变为无效,下面的代码报错
// println!("{}", name);
// 运行结果
// My name is ZhangSan
}
fn print_name(name: String) {
// 3. name 进入 print_name 作用域, 外部将无法访问 name 变量
println!("My name is {}", name);
} // 4. 函数结束,作用域失效,内存释放,name 变量也被释放
0x02 转移——从函数返回值
理解了向函数传递值的过程,那么从函数返回值也是同样的道理。
从函数返回值所有权转移 简易示意图
示例代码:
fn get_name() -> String {
// 1. 函数内创建 name 变量
let name = String::from("LiSi");
return String::from("My name is ") + name.as_str();
} // 2. 作用域结束,内存释放,name释放,将返回值的所有权转移至调用者
fn main() {
// 3. get_name 返回值的所有权转移至 name
let name = get_name();
// 4. 打印name
println!("{}", name);
// 运行结果
// My name is LiSi
}
0x03 转移与流程控制
再来了解一些其它场景中使用转移。
条件语句
在条件语句中使用转移。由于分支语句肯定会执行一个分支,因此我们可以在每个分支中去使用变量,但只会在一个分支发生转移。
fn print_dance(name: String) {
println!("{} 喜欢跳舞", name);
}
fn print_swim(name: String) {
println!("{} 喜欢游泳", name);
}
fn main() {
let x = 3 % 2;
let name = String::from("小明");
if x == 0 {
print_dance(name)
} else {
print_swim(name)
}
// 无法再次使用 name
// print_dance(name);
// 运行结果
// 小明 喜欢游泳
}
循环语句
由于循环体的特殊性,当第二次运行循环体时,上一次循环已经发生转移。所以下面的代码将会编译错误。
fn main() {
let name = String::from("rust");
for _ in 1..4 {
// 下面的代码 是错误的
// print_dance(name);
}
}
模式匹配
模式匹配与分支语句类似,不再赘述了,直接看下代码吧。
fn main() {
// 【匹配】
let x = 3 % 2;
let name = String::from("小明");
match x {
0 => {
print_dance(name);
}
1 => {
print_swim(name);
}
_ => {
println!("{}", name);
}
};
// 下面的代码 是错误的
// println!("{}", name);
// 运行结果
// 小明 喜欢游泳
}
0x04 小结
有关 Rust 转移的特性基本已经介绍完了。我相信读完文章的你没有感觉到它有多难,只是觉得这样的设计很新奇。总结下 Rust 所有权的几个核心特点吧:
- 所有权机制仅针对在堆上分配的数据,不包含基本类型。
- 变量与值的关系是绑定关系,变量拥有值的所有权。反过来讲。每一个值都存在一个所有者。每块内存空间都存在一个所有者。
- 当某一个变量离开当前所属的作用域后,变量将变为无效。
- 转移通常发生在变量间的赋值、向函数传值、从函数返回值这三大场景。
- 从目前来讲,所有的值有且只有一个所有者。
转载自:https://juejin.cn/post/7221740907233837116