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私服(三)

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

相关内容

热门资讯

宫颈机能不全孕妇险早产 紧急环... 大众卫生报·新湖南客户端2月26日讯(通讯员 曾可青)孕育生命本是一场满怀期许的旅程,但对宫颈机能不...
春节后“38消费”火热,李佳琦... 随着春节假期结束,消费市场并未降温,而是悄然完成了一次重心切换。作为开年首个重要消费节点,“38大促...
杨政昆率队专题调研企业融资难问... 2月26日,市委书记杨政昆率队专题调研企业融资难问题,现场办公推动破解民营企业融资堵点难点,切实为企...
面壁智能获数亿元新融资,中国电... IT之家 2 月 28 日消息,近日,面壁智能完成马年春节之后首轮融资,本轮融资规模数亿元,由中国电...
知名品牌突然宣布:关闭全国所有... 2月27日,不少消费者收到美国知名时尚品牌GUESS的官方通知短信,消息显示因经营模式调整,GUES...
原创 关... 当地时间2月20日,美国最高法院以6:3的投票结果,毫不客气地给特朗普来了一记响亮的耳光,裁定他依照...
邹云生调研服务联系企业、项目 按照区委统一安排部署,2月26日,区人大常委会主任邹云生来到双福街道、双福工业园、德感工业园,调研服...
营收增55.85%,利润降31... 2月28日,石头科技发布了2025年财报:总收入1,861,553.00万元,同比增长 55.85%...
成长板块轮动上涨,创业板ETF... 本周,创业板中盘200指数上涨2.9%,创业板成长指数上涨2.3%,创业板指数上涨1.0%。 申万宏...
A股指数分化,周期强势护盘|开... 2月27日,A股三大指数收盘涨跌不一,市场呈现明显结构性分化。截至收盘,上证指数涨0.39%,深证成...
一日五家银行披露首席合规官任职... 2026年2月27日,建设银行、交通银行、兰州银行、浙商银行及青岛农商行分别发布公告,披露首席合规官...
高市表态:反对女天皇 长安街知事消息,据环球网等媒体报道,2月27日,日本历史上首位女性首相高市早苗在国会就皇位继承问题表...
字节震惊世界,估值38000亿 字节跳动创始人张一鸣曾经说过:我做事从不设边界。 从字节跳动的不断扩张的商业帝国和连连刷新的估值来看...
原创 巴... 据英国媒体报道,近期巴拿马政府通过行政手段强行接管了长和系旗下的运河港口资产,这一举措引发了市场的广...
一年关闭32万家,烟酒店也不是... ▲这是灵兽第1770篇原创文章 烟酒利润归零时代来临,高端酒滞销、低价烟抢光,谁在买单? 作者/十里...
金价、银价、油价,上涨! 27日,中东地缘紧张局势推动市场避险情绪升温,加之美元指数下跌,国际金价上涨。截至收盘,纽约商品交易...
2026年国内TOP5推广平台... 流量成本持续走高,2026年的市场环境对推广提出了更高要求。 单一渠道通杀的时代已经过去,AI分发、...
2024-2003年上市公司企... 1.资料名称:2024-2003年上市公司企业机构投资者团体持股比例数据、机构投资者抱团数据 2.测...
营收大增27%,亚玛芬如何用多... 2月24日美东时间盘前,亚玛芬体育发布2025年第四季度及全年业绩。财报显示,亚玛芬体育2025年第...