系列文章

  1. Rust-引用与借用
  2. Rust-枚举和Match匹配

上一篇文章中,我们开始使用Rustling来学习Rust语言,本文我们将探讨在学习过程中遇到的第一个难点 引用与借用

导言

在Rustling的move_semantics6练习中我们将接触到Rust语言与其他编程语言最大的差异,引用和借用
让我们首先来看看题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let data = "Rust is great!".to_string();

get_char(data);

string_uppercase(&data);
}
// Should not take ownership
fn get_char(data: String) -> char {
data.chars().last().unwrap()
}
// Should take ownership
fn string_uppercase(mut data: &String) {
data = &data.to_uppercase();

println!("{}", data);
}

ps:题目中删除了一些不必要的注释,因为他们不重要

在声明的两个函数中,我们需要对参数字符串进行不同的操作,其中:

  • get_char(),要求我们返回字符串的最后一个字符
  • string_uppercase()要求我们将字符串转换为全大写字符
    从函数效果来看,不难发现,get_char()函数不需要我们对传入的参数进行修改,而string_uppercase()需要我们对传入的参数进行修改。

main()函数中,我们声明了一个变量data,并将字符串"Rust is Great!"雀食赋给了它,随后我们使用声明的两个函数get_char(),和string_uppercase()对这个变量进行操作。

问题

当我们运行这段代码的时候,出现了一点小小的问题,cargo告诉我们:

1
2
3
4
5
6
7
8
9
error[E0382]: borrow of moved value: `data`
--> exercises/move_semantics/move_semantics6.rs:15:22
13 | get_char(data);
| ---- value moved here
14 |
15 | string_uppercase(&data);
| ^^^^^ value borrowed here after move
error[E0716]: temporary value dropped while borrowed
error: aborting due to 2 previous errors

这里省略了一些输出,因为虽然他们很有用,但是放在文章阅读就不太友好了

原因与解决方案

上文两个error其实都是一个原因导致的:

  1. 我们先将data的所有权交给了get_char()函数
  2. 然后又将data借用给了string_uppercase()

get_char函数运行时,data的所有权已经转移给了它,待函数结束之后,data已经移出了作用域,所以后续的string_uppercase()就无法在借用data的值了

当然,我们的解决方法也很简单,根据注释来修改这两个函数的传入参数就可以了。
因为在get_char()中,我们不需要修改参数的值,所以这里应该传入的是一个借用。

1
2
3
fn get_char(data: &String/*这里修改为借用*/) -> char {
data.chars().last().unwrap()
}

而在string_uppercase()中,我们需要修改参数的值,所以这里应该获得参数的所有权

1
2
3
4
fn string_uppercase(mut data: String/*这里删除&*/) {
data = data.to_uppercase();
println!("{}", data);
}

最后再修改一下main就大功告成了
完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let data = "Rust is great!".to_string();

get_char(&data);

string_uppercase(data);
}

// Should not take ownership
fn get_char(data: &String) -> char {
data.chars().last().unwrap()
}

// Should take ownership
fn string_uppercase(mut data: String) {
data = data.to_uppercase();

println!("{}", data);
}