Rust 引用 借用

Rust 引用 && 借用

继续学rust
今天这篇文章主要跟随上一篇 Rust中的move而写的 引用和借用



主要内容

这里主要讲 rust 中的引用与借用,根据其中一些例子,尽量扯明白其中的关系和原理,讲的不对的留言,我及时更改


一、引用是什么?

在rust 中的引用是什么,引用有什么用。这是我们下面的主题之一。

先上代码

let r1 = String::from("hello world");// 注意这里没有mut
let r2 = &r1;// 注意这里没有mut

这个& 很神奇, 这样给 r2 赋值以后 不会产生 rust中的 move 操作
这里表示的就是引用,它们允许你使用值但不获取其所有权

  let r1_addr = &r1 as *const String as usize;
  let r2_addr = r2 as *const String as usize;
  
  println!("r1 value = {} address is 0x{}",r1,r1_addr);
  println!("r2 value = {} address is 0x{}",r2,r2_addr);

这里输出一下上面 r1 和 r2 的地址你会发现他们的地址是一致的
这就证明他们指向了同一块内存空间。

这里我们解释一下----“不获得其所有权”
就是我们r2 引用了 r1 的值 但是没有权限改变这片空间的值。

这里我们修改一下代码

let r1 = String::from("hello world");// 注意这里没有mut
let mut r2 = &r1;// 注意这里的mut
let tmp_str = String::from(", peace and love");

r2 =  &tmp_str;
let r1_addr = &r1 as *const String as usize;
let r2_addr = r2 as *const String as usize;

我们发现r2 的值可以正常更改,r2 已经指向了 tmp_str这个空间。

思考

那如果在被 r1 在被 r2 引用期间 r1 改变了值怎么办,或者说根据rust的设计原则, r1 允许被更改吗 ?????

错误代码示范,好孩子不要学

let mut r1 = String::from("hello world"); // 注意这里的mut
let mut r2 = &r1;  // 注意这里的mut

let tmp_str = String::from(", peace and love");
r1 = tmp_str;  // 肯定爆红的 错了哦这里

let r1_addr = &r1 as *const String as usize;
let r2_addr = r2 as *const String as usize;

我们看看提示的错误:

r1 = tmp_str;
^^ assignment to borrowedr1occurs here

这里提示: r1 这玩意已经被借走了.
所以不能改呀。

如果你把 r2 相关的代码注释掉肯定是可以的。或者如果r2 的作用域结束了也是可以的,这里大家可以设计一下这个代码自己实现,这里就不写了哦。

二、rust借用

将获取引用作为函数参数称为 借用
既然是借来的,肯定不能给人改了。
借来的东西你给人家改了,还回去时,还能还吗,所以是不允许修改的。

fn main() {
    let r1 = String::from("hello world ");

    change(&s);
}

fn change(r2: &String) {
    some_string.push_str(", peace and love");
}

fn change(r2: &String) {
------- use &mut String here to make mutable
r2.push_str(", world");
^^ cannot borrow as mutable

不允许修改引用的值

这里也体现了rust的设计原则之一:

  • 同一时间只有一个操作对同一片内存空间,要防止数据竞争

三、可变引用

其实在第一节里我已经用到了可变引用,这个没啥难以理解的。

总结一下就是

  • 加个 mut 不就可以了么。
  • 在特定作用域中的特定数据只能有一个可变引用。
let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);

自己检查错误吧,别总看,手动起来敲一下 ,加深印象看看报了什么错。

rust 的设计机制,关于数据多引用,涉及数据竞争的,在大部分情况下,代码编写的时候就会跟你提示错误,都不用编译。

四、悬垂引用

在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域

上面是rust程序语言设计里的解释,巴拉巴拉巴拉一大堆,

乍一看,这啥玩意啊。
鄙人的理解: 一个变量"B"被"C"引用了,这时"B"的生命周期结束,会被drop掉,"C"就无效了,完了你还想"A"去接着这个"C"。 就是这玩意。

不过好在要是发生这种情况,在你写代码时编译器就告诉你错了。除非你没安装插件提示。

fn main() {
    let A = dangle(); // A 去找 B了 ,找啥找
}

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

    &B  // 引用,B离开dangle会被drop掉,所有权没了引用也就失效了
}

这里铁定报错 expected lifetime parameter

总结

让我们概括一下之前对引用的讨论:

  • 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
  • 引用必须总是有效的。

参考文章:https://doc.rust-lang.org/book/ch05-01-defining-structs.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值