上一篇文章介绍了所有权,所有权是对数据有完全的操作权限,你对自己的手机有完全的所有权一样,你甚至可以选择销毁这个手机。但有时候,朋友可能借用一下你的手机打个电话,这时候,你仍然保持手机的所有权,只是给别人借用了一下。
我们可以看到一个复杂类型,比如String、Vec等,在赋值给另外一个变量后,就无法使用了。譬如下面的代码就会报错,如果还没搞清楚的,请回看上一篇文章。
fn foo(mut v: Vec) {
v.push(5);
}
fn main() {
let v = vec![];
foo(v);
println!("{:?}",v)
}
但日常的编程场景中,一个变量又会在多处使用。为了解决这个问题,rust 引入了一个新的概念:借用。我们可以通过借用修改一下上面的代码
fn foo(v: &mut Vec) { //参数类似是一个 Vec 的可变借用
v.push(5);
}
fn main() {
let mut v = vec![];
foo(&mut v); //借用
foo(&mut v); //再次借用
println!("{:?}",v) // 输出 [5, 5]
}
rust 里面的 & 代表借用,意思就是借用一下,当foo函数执行完成后,又还回来了,整个过程所有权没有发生转移(move)。而且还可以多次借用,上面故意写了两个 foo 函数调用。可变借用允许修改数据内容,就像你把手机借给别人,别人可能会重置部分手机设置一样。如果你不想让别人修改,可以使用不可变借用,把 mut 去掉。譬如我们只需要只读的方式 print 打印内容。如下:
fn main() {
let mut v = vec![];
foo(&mut v);
foo(&mut v);
print(&v); // 不可变借用 [5, 5]
print(&v); //不可变借用 [5, 5]
}
fn print(v: &Vec) {
println!("{:?}",v);
}
那么这个借用是如何实现的呢?譬如下面这段代码
fn main() {
let s1 = String::from("hello"); //s1 拥有所有权
let len = calculate_length(&s1); //s 借用
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
他们在内存的实现如下:s 代表借用,借用的本质是指向所有权的指针。
所以这里有一点非常重要,借用的生命的周期必须小于借用对象的生命周期,如果s1 生命的终止了,s 已经没有意义了。譬如下面的代码
fn main() {
let mut s1 = String::from("hello");
println!("len {}",s1.len()); //不可变借用 等效于 len(self: &String)
s1.push('!'); //可变借用
println!("len {}",s1.len()); //不可变借用
let v = s1; //转移(move)所有权了
println!("len {}",s1.len()); // 不可变借用出错
}
上面的代码最后一行就会报错,因为s1 所有权已经转移了,后续就不能借用了,这个其实也很好理解,当你把手机卖给了张三后,你就不能再借给李四使用了。
关于借用还有一个限制:&mut 可变借用同时只能存在一个,而不可变可以同时存在多个。这里为啥强调同时呢? 上面的例子已经可以看到,当多次执行foo 函数使用 &mut 可变借用追加元素的时候,没有报错,因为这些追加操作并非是同时发生的。而下面代码就会报错
fn main() {
let mut x = 1_i32;
let p = &mut x;
let v = &x; // 或者 let x =2 重新赋值 都不允许
println!("value of pointed : {}", p);
}
因为 p 这个借用的声明周期,是到最后一行打印才结束的。在这个p 的周期内,这个对象是冻结的,不允许发生其他借用或者修改其内容。这个其实也很好理解,主要就是为了考虑并发场景中数据的一致性。当你把手机借给李四了,你就无法再修改手机配置或者同时再借给张三了。但是多个不可变借用是可以同时存在的,因为他们之间是没有数据冲突的,都是只读的。譬如下面的代码,多个不可变借用是可以共存的。
fn main() {
let mut x = 1_i32;
let p = &x;
let v = &x;
println!("value of pointed : {}", p);
}
其实这个和读写锁本质上是一致的,如果某个线程获取了写锁,那么后续其他线程的读或者写都将被阻塞,但如果只是获得读锁,其他线程的写互斥,但读却并不阻塞。
页面更新:2024-05-12
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号