【Rust笔记】所有权(2)引用与借用

所有权 2 引用与借用

本人大蒟蒻,作为一个学习者稍微记录一下自己的理解。如有错误,请多多指教!

一、所有权与函数

所有权移动到函数参数

现在,我们来看看这个程序:

fn main() {
    let s = String::from("hello");
    
    print_string(s);
    
    println!("{}", s);
}

fn print_string(s: String) {
    println!("{}", s);
}

编译失败:

PS L:\Projects-Rust\rust-playground> cargo run
   Compiling rust-playground v0.1.0 (L:\Projects-Rust\rust-playground)
error[E0382]: borrow of moved value: `s`                                     
 --> src\main.rs:6:20
  |
2 |     let s = String::from("hello");
  |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
3 | 
4 |     print_string(s);
  |                 - value moved here
5 | 
6 |     println!("{}", s);
  |                    ^ value borrowed here after move
  |
  = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0382`.
error: could not compile `rust-playground` due to previous error

会发现它无法编译,给出的错误提示和 [所有者 1 所有者、移动、克隆](./所有者 1 所有者、移动、克隆.md) 中 **例子2 **的编译失败提示一样,也是 borrow of moved value

其实,在将 s 作为参数传给 printString() 的过程中也发生了一次 移动,而且没有再移动回来。

这不难理解,因为函数的参数本质上其实也是个 变量 嘛。

那么怎么办呢?

欸嘿,我再给它移回来不就好了!

通过返回值归还所有权

进行如下修改:

fn main() {
    let s = String::from("hello");
    
    let s = print_string(s);
    
    println!("{}", s);
}

fn print_string(s: String) -> String {
    println!("{}", s);
    s
}

输出:

PS L:\Projects-Rust\rust-playground> cargo run
   Compiling rust-playground v0.1.0 (L:\Projects-Rust\rust-playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.67s                
     Running `target\debug\rust-playground.exe`
hello
hello

成功运行。

然而,这么写多少有点 ,有没有更好的办法?答案是有,就是使用 引用

二、引用与借用

引用 其实像是一个指针,因为其实它是个地址,但是它又和指针不同,因为 它始终保证指向一个有效值

在声明 函数参数 的时候,可以为 参数类型 前添加一个 &,表明参数是 引用类型

对应的,传入参数 时也要在前面加一个 &,来创建一个对应的 引用

fn main() {
    let s = String::from("hello");
    
    print_string(&s);
    
    println!("{}", s);
}

fn print_string(s: &String) {
    println!("{}", s);
}

输出:

PS L:\Projects-Rust\rust-playground> cargo run
   Compiling rust-playground v0.1.0 (L:\Projects-Rust\rust-playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s                
     Running `target\debug\rust-playground.exe`
hello
hello

成功运行,没有问题。

此外,如果想要修改原变量,声明参数 以及 传入参数 时需要把 & 写为 &mut,这就是 可变引用

但是要注意,对一个变量,同时只能存在 一个 可变引用 或者 多个 不可变引用

而什么是 **借用(borrow)**呢?就是指 创建一个引用的行为

三、悬垂引用

看下面的程序:

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {
    let s = String::from("hello");

    &s
}

编译失败:

PS L:\Projects-Rust\rust-playground> cargo run
   Compiling rust-playground v0.1.0 (L:\Projects-Rust\rust-playground)
error[E0106]: missing lifetime specifier                                     
 --> src\main.rs:5:16
  |
5 | fn dangle() -> &String {
  |                ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime
  |
5 | fn dangle() -> &'static String {
  |                ~~~~~~~~

For more information about this error, try `rustc --explain E0106`.
error: could not compile `rust-playground` due to previous error

会发现它无法编译,为什么?

记不记得 引用指针 的重要区别?它始终保证指向一个有效值

关键还是在这一句话里面。

拥有者 s 在函数结束后便退出了作用域,会被销毁,但是返回的是对它的引用,这会导致 引用 指向一片 可能已经被分配给其它持有者内存。那么 Rust 肯定不允许这种事情发生咯。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Azur冰弦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值