rust所有权
一、堆和栈
栈和堆都是程序运行时使用的内存,但是它们的结构不同。
1.栈
栈,英文是stack。是内存的一段区域。
栈是后进先出形式的。就像薯片桶,先放进去的一片只能后拿出来。
栈上存储的数据大小必须是已知且固定的。也就是说如果一个变量或数据要放到栈上,那么它的大小在编译是就必须是明确的。
例如,类型为i32的变量,它的大小是固定4个字节。
2.堆
堆,英文是heap。是内存的另一段区域。堆内存也叫做资源。
堆是缺乏组织的:当向堆放入数据时,你要请求一定大小的空间。内存分配器在堆的某处找到一块足够大的空位,把它标记为已使用,并返回一个表示该位置地址的指针。这个过程称作在堆上分配内存。因为指针大小是已知且固定的,所以可以将该指针存储在栈上,不过当需要实际数据时,必须去指针指向的内存读取数据。就像一个围棋棋盘,你可以把一枚棋子放到任意可以放得下的位置。
在编译时大小未知或大小可能变化的数据,要存储在堆上。
堆不受系统管理,由用户自己管理,因此,使用不当,内存溢出的可能性就大大增加了。
Rust与其他语言的区别
(1)指针超出作用域会自动释放堆内存:
对于简单类型的栈内存(如int)超出作用域后自动释放,这个功能各个语言都有。而对于new出来的堆内存,在c/c++中要手动释放,在java中要委托垃圾回收释放。而垃圾回收不是实时的,会影响性能,手动释放又总会有人忘记释放。而Rust对栈内存和堆内存一视同仁,超出作用域一律自动释放,相当于自动delete指针。所以rust避免了内存泄漏。
在作用域结束时释放资源的模式称作资源获取即初始化(Resource Acquisition Is Initialization (RAII))。
rust强制使用raii,所以任何对象在离开作用域时,它的析构函数就被调用,然后它占有的资源就被释放。
这避免了资源泄漏,所以你再也不用手动释放内存或者担心内存泄漏。
(2)所有权:
某段内存只能被最后的变量名所有,前面声明过的变量都作废,这样一段内存就只有一个所有者,只有所有者可以释放这块内存。这有效避免了被多个变量释放的问题,而且该操作是在编译期的,这可在编译期就能避免空指针问题。比如c++中,a和b指向同一块内存,如果delete a之后,再delete b就会出错,而rust中不会出现这种问题。
二、所有权
(一)所有权是什么
所有权是指对内存资源的控制权和管理权。
在Rust中,每个值都有一个唯一的所有者。定义一个变量就是声明这个值由这个变量所有。所有的值最终都要存储在一块内存上,变量拥有这个值其实是拥有这块内存。栈内存所有者就是声明时的变量,而堆内存所有者是分配返回的指针。
只有所有者才能释放这块内存,其他人不能释放这块内存。
当所有者超出作用域时,会自动释放这块内存。
所有权的规则:
1.Rust中的每一个值都有一个所有者。
2.值在任一时刻有且只有一个所有者。
3.当所有者离开作用域,这个值将被丢弃。
比如,
现在可以把Box当成一个指针,后面章节再讲解Box用法。
fn create_box() {let _box1 = Box::new(3i32);// 在堆上分配一个整型数据// `_box1` 在这里被销毁,内存得到释放。如果是c++,就得手动delete,否则就会内存泄漏。这就是区别。
}
fn main() {let _box2 = Box::new(5i32);// 在堆上分配一个整型数据// 嵌套作用域:{let _box3 = Box::new(4i32);// 在堆上分配一个整型数据// `_box3` 在这里被销毁,内存得到释放}// 创建一大堆 box 完全不需要手动释放内存!for _ in 0u32..1000 {create_box();}// `_box2` 在这里被销毁,内存得到释放
}
(二)转让所有权
所有权可以转让。转让所有权也叫move。
就是由新变量拥有内存,旧变量变成无效的。
s1转让给s2,就像下图所示。s2拥有堆内存,s1变无效。
Rust语言中转让所有权的方式有以下几种:
1.把一个变量赋值给另一个变量。
2.把变量值传递给函数作为参数。
3.函数中返回一个变量作为返回值。
1.把一个变量赋值给另一个变量
fn main(){let a = Box::new(5i32);// a 是一个指向堆分配的整数的指针let b = a;// 移动a到b,把a的指针地址(而非数据)复制到b。现在是b拥有堆内存,a变无效。//println!("a contains: {}", a);// 报错!a无效,因为它不再拥有那部分堆上的内存。
}
2.把变量值传递给函数作为参数。
值传递方式,值的所有权也会发生变更
fn destroy_box(c: Box<i32>) {println!("Destroying a box that contains {}", c);// c 被销毁且内存得到释放
}
fn main() {let a = Box::new(5i32);// a 是一个指向堆分配的整数的指针destroy_box(a);// a的所有权转移给函数形参,a变无效//println!("a contains: {}", a);// 报错!a无效
}
3.函数中返回一个变量作为返回值
函数的形参获得的所有权将在离开函数后就失效了。失效的数据就再也访问不到了。
为了解决所有权失效的问题,我们可以让函数将所有者返回给调用者。
fn destroy_box(c: Box<i32>) ->Box<i32> {println!("Destroying a box that contains {}", c);c
}
fn main() {let mut a = Box::new(5i32);// a 是一个指向堆分配的整数的指针a = destroy_box(a);// a的所有权转移给函数形参,a变无效println!("b contains: {}", a);// 报错!a无效
}
(三)复刻
复刻,英文是clone。也叫深复制或深拷贝。
有时候,我们需要创建一个值的完全独立的副本,而不是转让所有权。在这种情况下,可以使用复刻。
创建s1的副本s2,就像下图所示。s1和s2都拥有了独立的所有权。
示例:
fn main() {let s1 = String::from("hello");let s2 = s1.clone();println!("{} {}", s1, s2); // 正常打印 "hello hello"
}
创建了字符串"hello"的副本,赋值给s2,因此s1和s2都拥有了独立的所有权。
fn main() {let a = Box::new(5i32);let b = a.clone();println!("{}", a);println!("{}", b);
}
栈上的数据
看下例
fn main() {let a = 50;let b = a;println!("{}", a);println!("{}", b);
}
这段代码能编译通过。按照所有权转让规则的话,它应该编译错误才对,可是为什么能编译通过?
因为像整型这样的类型完全存储在栈上,并不需要占用那么大的内存,所以拷贝它的值是很快的。没有理由在创建变量b后使a无效。这里没有深浅拷贝的区别,所以这里不管是否调用clone,效果都一样。
Rust有一个Copy trait,可以用于存储在栈上的类型。如果一个类型实现了Copy trait,那么就不使用所有权转让,而是使用复刻。
那么哪些类型实现了Copy trait呢?
Rust不允许自身或其部分实现了Drop trait的类型使用Copy trait。
任何简单标量值的组合都可以实现Copy,任何不在堆上分配内存的类型都可以实现Copy。
如下是一些Copy的类型:
1.布尔类型,bool
2.数字类型,包括整数和浮点数,比如 u32,f64。
3.字符类型,char
4.元组,当且仅当,其包含的类型都实现Copy的时候。比如,(i32, i32) 实现了Copy,但 (i32, String) 就没有。
相关文章:

rust所有权
一、堆和栈 栈和堆都是程序运行时使用的内存,但是它们的结构不同。 1.栈 栈,英文是stack。是内存的一段区域。 栈是后进先出形式的。就像薯片桶,先放进去的一片只能后拿出来。 栈上存储的数据大小必须是已知且固定的。也就是说如果一个变量…...

Win10电脑任务栏没有蓝牙图标的简单解决方法
Win10电脑任务栏没有蓝牙图标怎么办?在Win10电脑中,用户有时候会发现任务栏上没有蓝牙图标了,这样就无法通过蓝牙图标快速打开蓝牙服务了。下面小编给大家介绍最简单的解决方法,帮助大家找回任务栏上面的蓝牙图标吧。 问题原因 反…...
判断编译器类型、编译器版本、操作系统。
目录 1. 判断编译器类型: 2. 判断编译器版本: 3. 判断操作系统: 总结: 1. 判断编译器类型: 可以使用预定义的宏来判断编译器类型。例如,__GNUC__ 宏用于判断是否使用了GCC 编译器,_MSC_VER…...

百度实习一面(知识图谱部门)
百度面经(知识图谱部)一面 1.自我介绍 介绍完了,打开共享,对着简历一点一点问 2.ffmpeg在项目中是怎么使用的 回答了ffmpeg在项目中使用的命令,用来干了什么 3.为什么使用toml配置,了解过yml配置吗&am…...
Oracle 数据库查询优化
目录 1. Oracle 数据库查询优化(上百万级记录如何提高查询速度)2. Oracle SQL 性能优化 40 条 | 收藏了! 1. Oracle 数据库查询优化(上百万级记录如何提高查询速度) 对查询进行优化, 应尽量避免全表扫描, 首先应考虑在 where 及 order by 涉及的列上建立索引应尽量避免在 wher…...

时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测
时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测 目录 时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序…...

Java技术接单
今天给大家介绍一个阶段性(周期性)能获取一定收益的Java技术接单群,分享给大家!主要对搞Java的粉丝有帮助,因为可以赚点小钱,对Java技术的要求不高! 注意:首先进群不是免费的&#…...
多家企业发布基于大模型的AI产品,大模型应用落地哪家强?
https://m.mp.oeeee.com/a/BAAFRD000020230603805161.html “无产业不AI,无应用不AI。” 随着AI(人工智能)大模型技术落地,AI应用遍地开花。连日来,多家企业发布基于大模型的AI应用产品。身处“百模大战”时代&#x…...
如何在小程序中获取用户昵称、电话号,头像
一、如何获取昵称(获取微信昵称)以Taro框架为例 Taro框架中的组件Input的一个属性,type属性的值有一个nickname. 如果要拿到input的值,是要value结合onChange事件。 type"nickname" value{nickName} onChange{(value: …...

26606-2011 工业用氰乙酸甲酯 阅读笔记
声明 本文是学习GB-T 26606-2011 工业用氰乙酸甲酯. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了工业用氰乙酸甲酯的要求、试验方法、检验规则、标志、包装、运输、贮存和安全。 本标准适用于以氯乙酸、氰化钠、甲醇等为原料…...
微软开源 windows-drivers-rs, 用 Rust 开发 Windows 驱动程序
目录 1. 微软开源 windows-drivers-rs, 用 Rust 开发 Windows 驱动程序 1. 微软开源 windows-drivers-rs, 用 Rust 开发 Windows 驱动程序 Microsoft Azure 首席技术官兼著名 Windows 软件开发人员 Mark Russinovich 在社交平台上宣布, 启动了一个名为 windows-drivers-rs 的新…...
Java中判断字符串是否为合法数字
问题 最近遇到需要将String转BigDecimal的场景。 解决思路 利用NumberUtils.isCreatable判断是否为合法数字,然后,对字符串进行数字转换。注意:这里的NumberUtils类是org.apache.commons.lang3.math库里面的类。 Java if (NumberUtils.i…...
[LeetCode] Hard-2251. 花期内花的数目 - 二分查找/有序数组
Problem: 2251. 花期内花的数目 2251. 花期内花的数目 思路解题方法Code 思路 看题目应该是一道比较经典的差分,本来准备拿差分数组做的,后来搂了一眼题解,发现用二分的方法更简单 解题方法 此题有一种很简便的方法,第i个人到…...
VUE3父子组件传值defineProps() 和 defineEmits()
defineProps 和 defineEmits 都是只能在<script setup>中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。 官网传送门 父组件向子组件传值 defineProps 是 Vue3 中一种新的组件数据传递方式,可以用于在…...

OmniPlan Pro 4 for Mac:引领项目管理的创新与高效
OmniPlan Pro 4是一款强大且高效的项目管理工具,专为Mac用户设计。它提供了一套综合性的解决方案,帮助用户在Mac上便捷地进行项目规划、追踪和管理。凭借其直观的界面,用户可以快速上手,并且能充分利用这款工具的各种功能。 规划…...
封装JDBC,实现简单ORM框架
本文将封装JDBC的操作,实现简单的ORM框架,提供3种风格的api来给用户使用(1.原生jdbcSqlBuilder;2.类似jpa和mp的;3.注解接口方法) 代码仓库:malred/IFullORM 1. 原生JDBCsql构建器 第一步&…...

监控与运维,主流it运维监控工具
IT监管和运行维护已成为企业经营的关键环节。本文将详细介绍IT监管和运行维护的必要性、主要功能和实施策略,帮助企业实现数据安全和高效运行。 IT监管和运行维护的必要性 确保企业数据安全 IT监控系统可以实时监控企业网络、服务器、存储等关键设备的运行情况&…...
基于Matlab实现全局优化算法
Matlab是一种非常强大的数学建模和计算工具,它提供了许多优化算法的实现。全局优化算法是一种能够找到全局最优解的优化算法,相对于局部优化算法来说,具有更强的全局搜索能力。在本文中,我们将介绍如何使用Matlab实现全局优化算法…...
Kafka 笔记 (Non-Root/Container)
目录 1. Kafka 笔记 (Non-Root/Container)1.1. 启动1.2. bitnami/kafka1.2.1. Non-Root Containers 1. Kafka 笔记 (Non-Root/Container) 1.1. 启动 Kafka 需要与 ZooKeeper 一起启动: Kafka with ZooKeeper Run the following commands in order to start all services in…...

【Pytest】跳过执行之@pytest.mark.skip()详解
一、skip介绍及运用 在我们自动化测试过程中,经常会遇到功能阻塞、功能未实现、环境等一系列外部因素问题导致的一些用例执行不了,这时我们就可以用到跳过skip用例,如果我们注释掉或删除掉,后面还要进行恢复操作。 1、skip跳过成…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...