8、初识Rust – 引用与借用
在变量篇时,我们说过变量的所有权。当变量涉及到堆并且进行附值操作时,Rust只允许一个变量绑定该值。同样,当该值被函数调用时,变量所有权也会移交给调用函数,当函数执行完毕后如不做处理则会被自动释放。
fn main() { let a = String::from("hello"); test_function(a); println!("{a}"); } fn test_function(x: String) { println!("{x}"); }
如上代码,当变量a进入函数test_function时,所有权就会被移交给test_function。但是test_function后续并没有将该变量所有权移交,所以main函数最后的打印a变量的操作就会报错。
那么,如何才能解决该错误呢?也许我们可以这样。
fn main() { let a = String::from("hello"); let a = test_function(a); println!("{a}"); } fn test_function(x: String) -> String { println!("{x}"); x }
将x在函数内执行完成后,转移所有权给新的变量a,成功打印a变量。
当然这样也许有点麻烦,使用引用也可以达成这样的效果。
fn main() { let a = String::from("hello"); test_function(&a); println!("{a}"); } fn test_function(x: &String) { println!("{x}"); }
例如上面这个代码,将a传入test_function时,在a前增加一个&,并在test_function中也声明值为&引用。引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。与指针不同,引用确保指向某个特定类型的有效值。下面是如何定义并使用一个(新的)test_function
函数,它以一个对象的引用作为参数而不是获取值的所有权。如下就是引用的示意图。
引用是从该值的所有权的变量中借用过来的,正如名字一样,我们没有这个变量的所有权,最后使用完该变量后,还需要将所有权还给该变量。
如果我们尝试修改引用的变量时,就会抛出错误。
不过我们可以使用可变引用来实现对引用的修改。
fn main() { let mut a = String::from("hello"); test_function(&mut a); println!("{a}"); } fn test_function(x: &mut String) { println!("{x}"); x.push_str(",world"); }
如上一段代码,和使变量可变一样,在引用时加入mut即可将引用变量变为可变引用。可变引用有一个很大的限制:在同一时间只能有一个对某一特定数据的可变引用。这些尝试创建两个可变引用的代码会失败。
fn main() { let mut a = String::from("hello"); let b = &mut a; let c = &mut a; }
如上
–> src/main.rs:4:13
|
3 | let b = &mut a;
| —— first mutable borrow occurs here
4 | let c = &mut a;
| ^^^^^^ second mutable borrow occurs here
5 | println!(“{b},{c}”);
| – first borrow later used hereFor more information about this error, try `rustc –explain E0499`.
error: could not compile `master` due to previous error
并且可变引用与引用同时使用时也会抛出错误。
fn main() { let mut a = String::from("hello"); let b = &a; let c = &a; let d = &mut a; println!("{b},{c}"); }
–> src/main.rs:5:13
|
3 | let b = &a;
| — immutable borrow occurs here
4 | let c = &a;
5 | let d = &mut a;
| ^^^^^^ mutable borrow occurs here
6 | println!(“{b},{c}”);
| – immutable borrow later used hereFor more information about this error, try `rustc –explain E0502`.
warning: `master` (bin “master”) generated 1 warning
error: could not compile `master` due to previous error; 1 warning emitted