Rust中的所有权是什么
admin
2024-03-14 18:09:35
0

文章目录

    • 所有权规则
    • 变量作用域
    • 内存与分配
    • 变量与数据交互的方式
      • 移动
      • 克隆

所有权(系统)是 Rust 最为与众不同的特性,对语言的其他部分有着深刻含义。它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全,因此理解 Rust 中所有权如何工作是十分重要的。本文,我们将讲到所有权以及相关功能:借用(borrowing)、slice 以及 Rust 如何在内存中布局数据。
所有程序都必须管理其运行时使用计算机内存的方式。一些语言中具有垃圾回收机制,在程序运行时有规律地寻找不再使用的内存;在另一些语言中,程序员必须亲自分配和释放内存。Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。

所有权规则

  1. Rust 中的每一个值都有一个 所有者(owner)。
  2. 值在任一时刻有且只有一个所有者。
  3. 当所有者(变量)离开作用域,这个值将被丢弃。

变量作用域

既然我们已经掌握了基本语法,将不会在之后的例子中包含 fn main() { 代码,所以如果你是一路跟过来的,必须手动将之后例子的代码放入一个 main 函数中。这样,例子将显得更加简明,使我们可以关注实际细节而不是样板代码。
在所有权的第一个例子中,我们看看一些变量的 作用域(scope)。作用域是一个项(item)在程序中有效的范围。假设有这样一个变量:

let s = "hello";

变量 s 绑定到了一个字符串字面值,这个字符串值是硬编码进程序代码中的。这个变量从声明的点开始直到当前 作用域 结束时都是有效的。示例中的注释标明了变量 s 在何处是有效的。

fn main() {{                      // s 在这里无效, 它尚未声明let s = "hello";   // 从此处起,s 是有效的// 使用 s}                      // 此作用域已结束,s 不再有效
}

一个变量和其有效的作用域
换句话说,这里有两个重要的时间点:

  • 当 s 进入作用域 时,它就是有效的。
  • 这一直持续到它 离开作用域 为止。

目前为止,变量是否有效与作用域的关系跟其他编程语言是类似的。

内存与分配

就字符串字面值来说,我们在编译时就知道其内容,所以文本被直接硬编码进最终的可执行文件中。这使得字符串字面值快速且高效。不过这些特性都只得益于字符串字面值的不可变性。不幸的是,我们不能为了每一个在编译时大小未知的文本而将一块内存放入二进制文件中,并且它的大小还可能随着程序运行而改变。
对于 String 类型,为了支持一个可变,可增长的文本片段,需要在堆上分配一块在编译时未知大小的内存来存放内容。这意味着:

  • 必须在运行时向内存分配器(memory allocator)请求内存。
  • 需要一个当我们处理完 String 时将内存返回给分配器的方法。

第一部分由我们完成:当调用 String::from 时,它的实现 (implementation) 请求其所需的内存。这在编程语言中是非常通用的。
然而,第二部分实现起来就各有区别了。在有 垃圾回收(garbage collector,GC)的语言中, GC 记录并清除不再使用的内存,而我们并不需要关心它。在大部分没有 GC 的语言中,识别出不再使用的内存并调用代码显式释放就是我们的责任了,跟请求内存的时候一样。从历史的角度上说正确处理内存回收曾经是一个困难的编程问题。如果忘记回收了会浪费内存。如果过早回收了,将会出现无效变量。如果重复回收,这也是个 bug。我们需要精确的为一个 allocate 配对一个 free。
Rust 采取了一个不同的策略:内存在拥有它的变量离开作用域后就被自动释放。下面是示例 4-1 中作用域例子的一个使用 String 而不是字符串字面值的版本:

fn main() {{let s = String::from("hello"); // 从此处起,s 是有效的// 使用 s}                                  // 此作用域已结束,// s 不再有效
}

这是一个将 String 需要的内存返回给分配器的很自然的位置:当 s 离开作用域的时候。当变量离开作用域,Rust 为我们调用一个特殊的函数。这个函数叫做 drop,在这里 String 的作者可以放置释放内存的代码。Rust 在结尾的 } 处自动调用 drop。
注意:在 C++ 中,这种 item 在生命周期结束时释放资源的模式有时被称作 资源获取即初始化(Resource Acquisition Is Initialization (RAII))。如果你使用过 RAII 模式的话应该对 Rust 的 drop 函数并不陌生。
这个模式对编写 Rust 代码的方式有着深远的影响。现在它看起来很简单,不过在更复杂的场景下代码的行为可能是不可预测的,比如当有多个变量使用在堆上分配的内存时。现在让我们探索一些这样的场景。

变量与数据交互的方式

变量与数据交互方式主要有移动(Move)和克隆(Clone)两种:

移动

多个变量可以在 Rust 中以不同的方式与相同的数据交互:

let x = 5;
let y = x;

这个程序将值 5 绑定到变量 x,然后将 x 的值复制并赋值给变量 y。现在栈中将有两个值 5。此情况中的数据是"基本数据"类型的数据,不需要存储到堆中,仅在栈中的数据的"移动"方式是直接复制,这不会花费更长的时间或更多的存储空间。"基本数据"类型有这些:

  • 所有整数类型,例如 i32 、 u32 、 i64 等。
  • 布尔类型 bool,值为 true 或 false 。
  • 所有浮点类型,f32 和 f64。
  • 字符类型 char。
  • 仅包含以上类型数据的元组(Tuples)。

但如果发生交互的数据在堆中就是另外一种情况:

let s1 = String::from("hello");
let s2 = s1;

第一步产生一个 String 对象,值为 “hello”。其中 “hello” 可以认为是类似于长度不确定的数据,需要在堆中存储。
两个 String 对象在栈中,每个 String 对象都有一个指针指向堆中的 “hello” 字符串。在给 s2 赋值时,只有栈中的数据被复制了,堆中的字符串依然还是原来的字符串。
前面我们说过,当变量超出范围时,Rust 自动调用释放资源函数并清理该变量的堆内存。但是 s1 和 s2 都被释放的话堆区中的 “hello” 被释放两次,这是不被系统允许的。为了确保安全,在给 s2 赋值时 s1 已经无效了。没错,在把 s1 的值赋给 s2 以后 s1 将不可以再被使用。下面这段程序是错的:

let s1 = String::from("hello");
let s2 = s1; 
println!("{}, world!", s1); // 错误!s1 已经失效

克隆

Rust会尽可能地降低程序的运行成本,所以默认情况下,长度较大的数据存放在堆中,且采用移动的方式进行数据交互。但如果需要将数据单纯的复制一份以供他用,可以使用数据的第二种交互方式——克隆。

fn main() {let s1 = String::from("hello");let s2 = s1.clone();println!("s1 = {}, s2 = {}", s1, s2);
}

运行结果:

s1 = hello, s2 = hello

这里是真的将堆中的 “hello” 复制了一份,所以 s1 和 s2 都分别绑定了一个值,释放的时候也会被当作两个资源。
当然,克隆仅在需要复制的情况下使用,毕竟复制数据会花费更多的时间。

本文内容到此结束了,
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位指出。
主页:共饮一杯无的博客汇总👨‍💻

保持热爱,奔赴下一场山海。🏃🏃🏃

上一篇:Nexus私服(三)

下一篇:基础医学概论试题

相关内容

热门资讯

中国银行招标结果:中国银行北京... 证券之星消息,根据天眼查APP-财产线索数据整理,中国银行股份有限公司5月24日发布《中国银行北京庄...
原创 A... "上下同欲者胜。"——《孙子兵法》 “厂家那边又逼我压两百万的货,可库存早都冒了。” 凌晨两点...
原创 “... 全款买房”和贷款30年,差别到底有多大?曹德旺一句话点醒了很多人 前阵子,一个朋友把看了半年的房子终...
云英谷科技登陆港交所:AI终端... 5月27日,云英谷科技股份有限公司(股票简称:云英谷科技,股票代码:3310.HK)成功登陆港交所主...
京东集团与三一集团签订战略合作... 5月25日,京东集团与三一集团在北京签署战略合作协议。京东集团SEC副主席、京东集团CEO许冉与三一...
青岛的朋友看过来:黄金回收我跑... 前阵子想把家里一些旧金饰处理掉,在青岛问了几家回收黄金的地方。今天就跟大家随便聊聊我打听、上门、对比...
武汉有闲置贵重金属变现需求该怎... 不少有黄金回收需求的用户不知道该如何挑选合适的服务机构,其实只要从资质、专业度、服务能力、口碑几个维...
业绩再度下滑,石药集团一季度归... 图片来源:视觉中国 蓝鲸新闻5月27日讯(记者 屠俊)5月27日午间,石药集团(01093.HK)公...
蚂蚁CEO韩歆毅:在Agent... 【CNMO科技消息】近日,蚂蚁集团CEO韩歆毅在演讲中,系统分享了关于智能体经济和AI支付的底层思考...
Buff叠满!芯片,双重利好!... 芯片领域,传来两则大消息! 一是5月27日有媒体报道称,台积电3纳米制程下半年将涨价15%,明年或再...
“全球正面临第五次油价冲击” 日本央行行长植田和男27日在东京说,自上世纪70年代以来,全球多次经历能源价格急剧上涨,当前全球正面...
白酒股,直线拉升!600779... 【导读】白酒股终于涨了 中国基金报记者 泰勒 大家好,花有重开日,人无再少年。就在刚刚,低迷许久的“...
河北地区闲置名酒如何合规变现 闲置名酒处置的行业现状 近年来随着居民酒类收藏意识的逐步提升,不少家庭都存有不同品类的年份名酒,当...
重磅!长鑫科技科创板IPO获通... 5月27日消息,长鑫科技科创板IPO获上交所上市委会议通过。
东方基金开展“一司一省一高校”... 为深入贯彻落实新“国九条”以及《推动公募基金高质量发展行动方案》的核心要求,积极响应证监会对于金融机...
那句「都是卖猪食的」,为什么你... 你大概也笑了一下。 最近有句话在网上传疯了,说字节的副总裁回怼腾讯的“短视频像猪食”,撂了一句“都是...
2026 年小红书多账号管理工... 摘要 2026 年小红书矩阵运营成品牌获客主流,但账号风控严、消息分散、转化低效等痛点突出。本文基...
打着高知女性旗号割韭菜,“五个... 出品丨搜狐财经 作者丨柴鑫洋 编辑丨李文贤 你被“五个女博士”种草过吗? 打着高知女性旗号,却做着低...
A股董责险渗透率破32%,海南... 开栏语: 保险是经济的“减震器”,但保险条款复杂晦涩,犹如海下暗礁。 即日起,海财经·证券导报开设“...
奥尼电子:49万股限制性股票将... 5月27日,奥尼电子(301189)发布公告,2025年限制性股票激励计划第一个归属期归属结果已确定...