Nicksxs's Blog

What hurts more, the pain of hard work or the pain of regret?

0%

# rust学习笔记-所有权二

发表于 2021-04-18 更新于 2022-06-11 分类于 语言 ， Rust 阅读次数： 阅读次数： Disqus：

这里需要说道函数和返回值了
可以看书上的这个例子
对于这种情况，当进入函数内部时，会把传入的变量的所有权转移进函数内部，如果最后还是要返回该变量，但是如果此时还要返回别的计算结果，就可能需要笨拙地使用元组

### 引用

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

    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()
    }

这里的&符号就是引用的语义，它们允许你在不获得所有权的前提下使用值
由于引用不持有值的所有权，所以当引用离开当前作用域时，它指向的值也不会被丢弃

### 可变引用

而当我们尝试对引用的字符串进行修改时

    fn main() {
        let s1 = String::from("hello");
        change(&s1);
    }
    fn change(s: &String) {
        s.push_str(", world");
    }

就会有以下报错，
其实也很容易发现，毕竟没有 mut 指出这是可变引用，同时需要将 s1 改成 mut 可变的

    fn main() {
        let mut s1 = String::from("hello");
        change(&mut s1);
    }

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

再看一个例子

    fn main() {
        let mut s1 = String::from("hello");
        let r1 = &mut s1;
        let r2 = &mut s1;
    }

这个例子在书里是会报错的，因为同时存在一个以上的可变引用，但是在我运行的版本里前面这段没有报错，只有当我真的要去更改的时候

    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 想要避免这类多重可变更导致的异常问题，总结下就是三个点

- 两个或两个以上的指针同时同时访问同一空间
- 其中至少有一个指针会想空间中写入数据
- 没有同步数据访问的机制
  并且我们不能在拥有不可变引用的情况下创建可变引用

### 悬垂引用

还有一点需要注意的就是悬垂引用

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

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

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

### 总结

最后总结下

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