rust学习笔记-所有权二

这里需要说道函数和返回值了
可以看书上的这个例子

对于这种情况,当进入函数内部时,会把传入的变量的所有权转移进函数内部,如果最后还是要返回该变量,但是如果此时还要返回别的计算结果,就可能需要笨拙地使用元组

引用

此时我们就可以用引用来解决这个问题

1
2
3
4
5
6
7
8
9
fn 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
7
fn 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
9
fn main() {
let mut s1 = String::from("hello");
change(&mut s1);
}


fn change(s: &mut String) {
s.push_str(", world");
}

再看一个例子

1
2
3
4
5
fn 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
12
fn 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
8
fn main() {
let reference_to_nothing = dangle();
}

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

这里可以看到其实在 dangle函数返回后,这里的 s 理论上就离开了作用域,但是由于返回了 s 的引用,在 main 函数中就会拿着这个引用,就会出现如下错误

总结

最后总结下

  • 在任何一个段给定的时间里,你要么只能拥有一个可变引用,要么只能拥有任意数量的不可变引用。
  • 引用总是有效的。