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 here

For 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 here

For 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