rust学习笔记-所有权二
这里需要说道函数和返回值了
可以看书上的这个例子
对于这种情况,当进入函数内部时,会把传入的变量的所有权转移进函数内部,如果最后还是要返回该变量,但是如果此时还要返回别的计算结果,就可能需要笨拙地使用元组
引用
此时我们就可以用引用来解决这个问题1
2
3
4
5
6
7
8
9fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
这里的&符号就是引用的语义,它们允许你在不获得所有权的前提下使用值
由于引用不持有值的所有权,所以当引用离开当前作用域时,它指向的值也不会被丢弃
可变引用
而当我们尝试对引用的字符串进行修改时1
2
3
4
5
6
7fn main() {
let s1 = String::from("hello");
change(&s1);
}
fn change(s: &String) {
s.push_str(", world");
}
就会有以下报错,
其实也很容易发现,毕竟没有 mut 指出这是可变引用,同时需要将 s1 改成 mut 可变的1
2
3
4
5
6
7
8
9fn main() {
let mut s1 = String::from("hello");
change(&mut s1);
}
fn change(s: &mut String) {
s.push_str(", world");
}
再看一个例子1
2
3
4
5fn main() {
let mut s1 = String::from("hello");
let r1 = &mut s1;
let r2 = &mut s1;
}
这个例子在书里是会报错的,因为同时存在一个以上的可变引用,但是在我运行的版本里前面这段没有报错,只有当我真的要去更改的时候1
2
3
4
5
6
7
8
9
10
11
12fn main() {
let mut s1 = String::from("hello");
let mut r1 = &mut s1;
let mut r2 = &mut s1;
change(&mut r1);
change(&mut r2);
}
fn change(s: &mut String) {
s.push_str(", world");
}
这里可能就是具体版本在实现上的一个差异,我用的 rustc 是 1.44.0 版本
其实上面的主要是由 rust 想要避免这类多重可变更导致的异常问题,总结下就是三个点
- 两个或两个以上的指针同时同时访问同一空间
- 其中至少有一个指针会想空间中写入数据
- 没有同步数据访问的机制
并且我们不能在拥有不可变引用的情况下创建可变引用
悬垂引用
还有一点需要注意的就是悬垂引用1
2
3
4
5
6
7
8fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
这里可以看到其实在 dangle函数返回后,这里的 s 理论上就离开了作用域,但是由于返回了 s 的引用,在 main 函数中就会拿着这个引用,就会出现如下错误
总结
最后总结下
- 在任何一个段给定的时间里,你要么只能拥有一个可变引用,要么只能拥有任意数量的不可变引用。
- 引用总是有效的。