前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >18.Rust-所有权和移动

18.Rust-所有权和移动

原创
作者头像
面向加薪学习
修改2022-09-04 11:38:37
3750
修改2022-09-04 11:38:37
举报
文章被收录于专栏:面向加薪学习面向加薪学习

因为变量要负责释放它们拥有的资源,所以资源只能拥有一个所有者。这也防止了资源的重复释放。注意并非所有变量都拥有资源(例如引用)。

在进行赋值(let a = b)或通过值来传递函数参数(foo(a))的时候,资源的所有权(ownership)会发生转移。按照 Rust 的规范,这被称为资源的移动(move)。

在移动资源之后,原来的所有者不能再被使用,这可避免悬挂指针(dangling pointer)的产生。

内存分为两大类:栈(stack)堆(heap)

它是一种 后进先出 的机制,类似我们日常的落盘子,只能一个一个向上方,然后从最上面拿一个盘子。一个变量要放到栈上,那么它的大小在编译时就要明确。i32 类型的变量,它就占用 4 个字节。Rust 中可以放到栈上的数据类型,他们的大小都是固定的。如果是字符串,在运行时才会赋值的变量,在编译期的时候大小是未知或不确定的。所以字符串类型存储在上。

用于编译时大小未知或不确定的,只有运行时才能确定的数据。在上存储一些动态类型的数据。是不受系统管理的,是用户自己管理的,也增加了内存溢出的风险。

所有权

所有权就是值一个东西归属谁。Rust 中一个变量对应一个值,变量就称为这个值得所有者

代码语言:txt
复制
let name="从0到Go语言微服务架构师";

这句话的意思就是,"从 0 到 Go 语言微服务架构师" 这个值所在内存块由变量 name 所有。

Rust 中,只能由一个所有者,不允许两个同时指向同一块内存区域。变量必须指向不同的内存区域。

转让所有权

类似我们人类把一个东西送人或丢弃。

以下几种方式转让所有权:

  1. 把一个变量赋值给另一个变量。
代码语言:txt
复制
   fn main() {
        // 栈分配的整型
        let a = 88;
        // 将 `a` *复制*到 `b`——不存在资源移动
        let b = a;
        // 两个值各自都可以使用
        println!("a {}, and b {}", a, b);

       let v1 = vec!["Go语言极简一本通","Go语言微服务架构核心22讲","从0到Go语言微服务架构师"];
       let v2 =v1;
       println!("{:?}",v1);
   }

   报错如下:
   error[E0382]: borrow of moved value: `v1`
   let v1 = vec!["Go语言极简一本通","Go语言微服务架构核心22讲","从0到Go语言微服务架构师"];
   | -- move occurs because `v1` has type `Vec<&str>`, which does not implement the `Copy` trait
   9 | let v2 =v1;
   | -- value moved here
   10 | println!("{:?}",v1);
   | ^^ value borrowed here after move
   |
  • v1 拥有堆上数据的所有权。(每次只能有一个变量对堆上数据有所有权)
  • v2=v1 v2 拥有了堆上数据的所有权。
  • v1 已经没有对数据的所有权了,所以再使用 v1 会报错。
  • 如果 Rust 检查到 2 个变量同时拥有堆上内存的所有权。会报错如上。
  • 把变量传递给函数参数。
代码语言:txt
复制
fn show(v:Vec<&str>){
    println!("v {:?}",v)
}
fn main() {
    let studyList = vec!["Go语言极简一本通","Go语言微服务架构核心22讲","从0到Go语言微服务架构师"];
    //studyList 拥有堆上数据管理权
    let studyList2 = studyList;
    // studyList 将所有权转义给了 studyList2
    show(studyList2);
    // studyList2 将所有权转让给参数 v,studyList2 不再可用。
    println!("studyList2 {:?}",studyList2);
    //studyList2 已经不可用。
}

error[E0382]: borrow of moved value: `studyList2`
| let studyList2 = studyList; // studyList 将所有权转义给了 studyList2
| ---------- move occurs because `studyList2` has type `Vec<&str>`, which does not implement the `Copy` trait
| show(studyList2); // studyList2 将所有权转让给参数 v,studyList2 不再可用。
| ---------- value moved here
| println!("studyList2 {:?}",studyList2);//studyList2 已经不可用。
| ^^^^^^^^^^ value borrowed here after move
  1. 函数中的返回值。
代码语言:txt
复制
fn show2(v:Vec<&str>) -> Vec<&str>{
    println!("v {:?}",v);
    return v;
}

fn main() {
    let studyList3 = vec!["Go语言极简一本通","Go语言微服务架构核心22讲","从0到Go语言微服务架构师"];
    let studyList4 = studyList3;
    let result = show2(studyList4);
    println!("result {:?}",result);
    //输出 result ["Go语言极简一本通", "Go语言微服务架构核心22讲", "从0到Go语言微服务架构师"]
}

基础数据类型与所有权

所有权只会发生在堆上分配的数据,基础数据类型(整型,浮点型,布尔,字符)存储在栈上,所以没有所有权的概念。基础类型可以认为是值拷贝,在内存上另外的地方,存储和复制来的数据,然后让新的变量指向它。

代码语言:txt
复制
let a = 88;
let b = a;
println!("a {}, and b {}", a, b);

总结

赋值并不是唯一涉及移动的操作。值在作为参数传递或从函数返回时也会被移动:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
    • 所有权
      • 转让所有权
        • 基础数据类型与所有权
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档