当前位置: 首页 > news >正文

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所有权

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

Win10电脑任务栏没有蓝牙图标的简单解决方法

Win10电脑任务栏没有蓝牙图标怎么办&#xff1f;在Win10电脑中&#xff0c;用户有时候会发现任务栏上没有蓝牙图标了&#xff0c;这样就无法通过蓝牙图标快速打开蓝牙服务了。下面小编给大家介绍最简单的解决方法&#xff0c;帮助大家找回任务栏上面的蓝牙图标吧。 问题原因 反…...

判断编译器类型、编译器版本、操作系统。

目录 1. 判断编译器类型&#xff1a; 2. 判断编译器版本&#xff1a; 3. 判断操作系统&#xff1a; 总结&#xff1a; 1. 判断编译器类型&#xff1a; 可以使用预定义的宏来判断编译器类型。例如&#xff0c;__GNUC__ 宏用于判断是否使用了GCC 编译器&#xff0c;_MSC_VER…...

百度实习一面(知识图谱部门)

百度面经&#xff08;知识图谱部&#xff09;一面 1.自我介绍 介绍完了&#xff0c;打开共享&#xff0c;对着简历一点一点问 2.ffmpeg在项目中是怎么使用的 回答了ffmpeg在项目中使用的命令&#xff0c;用来干了什么 3.为什么使用toml配置&#xff0c;了解过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技术接单

今天给大家介绍一个阶段性&#xff08;周期性&#xff09;能获取一定收益的Java技术接单群&#xff0c;分享给大家&#xff01;主要对搞Java的粉丝有帮助&#xff0c;因为可以赚点小钱&#xff0c;对Java技术的要求不高&#xff01; 注意&#xff1a;首先进群不是免费的&#…...

多家企业发布基于大模型的AI产品,大模型应用落地哪家强?

https://m.mp.oeeee.com/a/BAAFRD000020230603805161.html “无产业不AI&#xff0c;无应用不AI。” 随着AI&#xff08;人工智能&#xff09;大模型技术落地&#xff0c;AI应用遍地开花。连日来&#xff0c;多家企业发布基于大模型的AI应用产品。身处“百模大战”时代&#x…...

如何在小程序中获取用户昵称、电话号,头像

一、如何获取昵称&#xff08;获取微信昵称&#xff09;以Taro框架为例 Taro框架中的组件Input的一个属性&#xff0c;type属性的值有一个nickname. 如果要拿到input的值&#xff0c;是要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判断是否为合法数字&#xff0c;然后&#xff0c;对字符串进行数字转换。注意&#xff1a;这里的NumberUtils类是org.apache.commons.lang3.math库里面的类。 Java if (NumberUtils.i…...

[LeetCode] Hard-2251. 花期内花的数目 - 二分查找/有序数组

Problem: 2251. 花期内花的数目 2251. 花期内花的数目 思路解题方法Code 思路 看题目应该是一道比较经典的差分&#xff0c;本来准备拿差分数组做的&#xff0c;后来搂了一眼题解&#xff0c;发现用二分的方法更简单 解题方法 此题有一种很简便的方法&#xff0c;第i个人到…...

VUE3父子组件传值defineProps() 和 defineEmits()

defineProps 和 defineEmits 都是只能在<script setup>中使用的编译器宏。他们不需要导入&#xff0c;且会随着 <script setup> 的处理过程一同被编译掉。 官网传送门 父组件向子组件传值 defineProps 是 Vue3 中一种新的组件数据传递方式&#xff0c;可以用于在…...

OmniPlan Pro 4 for Mac:引领项目管理的创新与高效

OmniPlan Pro 4是一款强大且高效的项目管理工具&#xff0c;专为Mac用户设计。它提供了一套综合性的解决方案&#xff0c;帮助用户在Mac上便捷地进行项目规划、追踪和管理。凭借其直观的界面&#xff0c;用户可以快速上手&#xff0c;并且能充分利用这款工具的各种功能。 规划…...

封装JDBC,实现简单ORM框架

本文将封装JDBC的操作&#xff0c;实现简单的ORM框架&#xff0c;提供3种风格的api来给用户使用&#xff08;1.原生jdbcSqlBuilder&#xff1b;2.类似jpa和mp的&#xff1b;3.注解接口方法&#xff09; 代码仓库&#xff1a;malred/IFullORM 1. 原生JDBCsql构建器 第一步&…...

监控与运维,主流it运维监控工具

IT监管和运行维护已成为企业经营的关键环节。本文将详细介绍IT监管和运行维护的必要性、主要功能和实施策略&#xff0c;帮助企业实现数据安全和高效运行。 IT监管和运行维护的必要性 确保企业数据安全 IT监控系统可以实时监控企业网络、服务器、存储等关键设备的运行情况&…...

基于Matlab实现全局优化算法

Matlab是一种非常强大的数学建模和计算工具&#xff0c;它提供了许多优化算法的实现。全局优化算法是一种能够找到全局最优解的优化算法&#xff0c;相对于局部优化算法来说&#xff0c;具有更强的全局搜索能力。在本文中&#xff0c;我们将介绍如何使用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介绍及运用 在我们自动化测试过程中&#xff0c;经常会遇到功能阻塞、功能未实现、环境等一系列外部因素问题导致的一些用例执行不了&#xff0c;这时我们就可以用到跳过skip用例&#xff0c;如果我们注释掉或删除掉&#xff0c;后面还要进行恢复操作。 1、skip跳过成…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...