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

5.所有权

标题

  • 一、概念
  • 二、规则
  • 三、示例
    • 3.1 变量作用域
    • 3.2 所有权的移交(深拷贝与浅拷贝)
    • 3.3 函数与所有权
    • 3.4 返回值与作用域
    • 3.5 引用的使用
  • 四、切片(&str)

一、概念

  • 所有权是Rust的核心特性。
  • 所有程序在运行时都必须管理它们使用计算机内存的方式。Rust的内存是通过一个所有权系统来管理的,其中包含一组编译器在编译时检查的规则。
  • 在Rust中,一个值是在栈还是堆上对语言的行为和为什么要做某些决定是有更大的影响的。
  • Rust通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。在运行时,所有权系统的任何功能都不会减慢程序。

二、规则

  • Rust 中的每一个值都有一个被称为其所有者(owner)的变量;
  • 值在任一时刻有且只有一个所有者
  • 当所有者(变量)离开作用域,这个值将被丢弃
  • 函数参数的传递也会造成所有权的转移;
  • 使用引用可以只使用变量而不转移所有权;
  • 一个引用的作用域从声明的地方开始一直持续到最后一次使用为止;

三、示例

3.1 变量作用域

  • 下面的变量x超出了{}的作用域范围,打印时报错cannot find value x in this scope
  • hello变量自动在堆内存中申请了空间,并且初始化为hello,等出了作用域(倒数第二个“}”号)后自动调用drop函数释放内存。
fn main() {{let x =  3;} println!("x = {}", x);  //cannot find value `x` in this scope{let hello =  String::from("hello");println!("hello  = {}", hello );}
}

3.2 所有权的移交(深拷贝与浅拷贝)

  • 在堆上申请的内存,会在连续赋值的时候进行内存所有权的移交。
  • 可以使用clone函数进行堆内存的深拷贝
fn main() {let x = 5;let y = x;  //栈内存,没有任何影响let h = String::from("HelloWorld!");let l = h;   //已经进行了所有权的移交,h已不存在//let l = h.clone();  //可以使用clon()函数重新申请空间//println!("h = {}",h);  //error: value borrowed here after move(clone除外)println!("l = {}",l);
}

3.3 函数与所有权

将值传递给函数在语义上与给变量赋值相似。所有权转移的规则也相同

fn main() {let s = String::from("Hello");take_ownership(s);  //这里s发生了转移 let x = 5;makes_copy(x);     //栈上的变量x不受所有权影响println!("{} {}", x, s);   //s的所有权在take_ownership里,因此这里无法打印
}fn take_ownership(src: String){println!("{}", src);
}fn makes_copy(src: i32){println!("{}", src)
}

3.4 返回值与作用域

返回值可以把内存空间的所有权返回

fn main() {let s1 = gives_ownership(); //来源于gives_ownership中的some_stringlet s2 = String::from("hello");  let s3 = takes_and_gives_back(s2);  //通过该函数所有权从s2转移到了s3println!("{}{}{}", s1, s2, s3);   //s2编译报错}fn gives_ownership() -> String {let src = String::from("hello"); src   //返回src的所有权
}fn takes_and_gives_back(a_string: String) -> String{a_string
}

3.5 引用的使用

在参数中使用引用就可以只传递变量而不传递所有权

fn main() {let mut s = String::from("Hello");alter_string_value(&mut s);  //只传递s的值而不转移所有权println!("{}", s);   //s依然有效,输出“Hello,world”
}fn alter_string_value(src: &mut String){  //可变引用src.push_str(",world");
}fn print_string_value(src: &String){src.push_str(",world");  //不可变引用,不能修改
}

在同一时间,只能有一个对某一特定数据的可变引用,尝试创建两个可变引用的代码将会失败。

fn main() {let mut s = String::from("hello");let r1 = &mut s;let r2 = &mut s;println!("{}, {}", r1, r2);
}

报错信息如下
在这里插入图片描述
这个报错说这段代码是无效的,我们不能在同一个作用域内多次将 s 作为可变变量。第一个可变的引用在 r1 中,并且必须持续到在 println! 中使用它,但是在那个可变引用的创建和它的使用之间,我们又尝试在 r2 中创建另一个可变引用,它引用了与 r1 相同的数据。

这样做是为了避免数据竞争,数据竞争由三个行为造成:

  • 两个或更多指针同时访问同一数据。
  • 至少有一个指针被用来写入数据。
  • 没有同步数据访问的机制。

禁止同时使用可变与不可变引用

fn main() {let mut s = String::from("hello");let r1 = &s; // 没问题let r2 = &s; // 没问题let r3 = &mut s; // 大问题println!("{}, {}, and {}", r1, r2, r3);
}

改成下面这样就行了,依然是作用域的问题。

fn main() {let mut s = String::from("hello");let r1 = &s; // 没问题let r2 = &s; // 没问题println!("{} {}", r1, r2);let r3 = &mut s; // 没问题println!("{}", r3);
}

四、切片(&str)

  • 切片(slice)允许引用集合中一段连续的元素序列,而不用引用整个集合;
  • 字符串字面量就是切片,因此它是不可变的;
  • 可以采用字符串切片&str作为参数类型,因此这样就可以同时接收String和&str类型的参数了;
  • 定义函数时使用字符串切片代替字符串引用会使我们的API更加通用,且不会损失任何功能;

切片示例

fn main() {let s = String::from("hello world!");let hello = &s[0..5];  //hello,取0到4字符, 也可以写成&s[..5]let world = &s[5..];   //world,取6到最后let whole = &s[..];  //整个字符串// s.clear();println!("*{}*",hello);  //*hello*println!("*{}*",world);  //* world!*println!("{}", whole);   //hello world!
}

函数示例

fn main() {let s = String::from("hello world!");let wordIndex = first_world(&s[..]); //使用完整的切片println!("wordIndex = {}", wordIndex);let my_string_literal = "hello world";let wordIndex = first_world(&my_string_literal);println!("wordIndex = {}", wordIndex);}//获得第一个单词
fn first_world(s: &str) -> &str {let bytes = s.as_bytes(); //转换为字节序for (index, &item) in bytes.iter().enumerate(){if item == b' ' {return &s[..index];}}&s[..]
}

相关文章:

5.所有权

标题 一、概念二、规则三、示例3.1 变量作用域3.2 所有权的移交(深拷贝与浅拷贝)3.3 函数与所有权3.4 返回值与作用域3.5 引用的使用 四、切片(&str) 一、概念 所有权是Rust的核心特性。所有程序在运行时都必须管理它们使用计算机内存的方式。Rust的…...

RabbitMQ-工作模式(Publish模式Routing模式)

文章目录 发布/订阅(Publish/Subscribe)交换机临时队列绑定总体代码示例 路由(Routing)绑定直连交换机多重绑定发送日志订阅总体代码示例 更多相关内容可查看 发布/订阅(Publish/Subscribe) 构建一个简单的…...

【机器学习算法】期望最大化(EM)算法概述

期望最大化(EM)算法是一种迭代算法,用于在有未观测变量的情况下,求解概率模型参数的最大似然估计或最大后验估计。以下是对EM算法的原理与应用进行详细地剖析: EM算法原理 E步 - 期望计算:根据当前估计的模…...

【深度学习】数竹签演示软件系统

往期文章列表: 【YOLO深度学习系列】图像分类、物体检测、实例分割、物体追踪、姿态估计、定向边框检测演示系统【含源码】 【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】 【深度学习】YOLOV8数据标注及模型训练方法整…...

Halcon 多相机统一坐标系

小杨说事-基于Halcon的多相机坐标系统一原理个人理解_多相机标定统一坐标系-CSDN博客 一、概述 最近在搞多相机标定等的相关问题,对于很大的场景,单个相机的视野是不够的,就必须要统一到一个坐标系下,因此我也用了4个相机&#…...

Apache Kylin:大数据分析从入门到精通

一、Kylin简介 Apache Kylin是一个分布式数据分析引擎,专为处理海量数据设计,能够在极短时间内对超大规模数据集进行OLAP(Online Analytical Processing)分析。Kylin通过预计算和高效的查询机制,为用户提供秒级的查询响应时间,支持与Hadoop、Hive、HBase等大数据平台无缝…...

SQL Server 2016导入.bak文件到数据库里面步骤

1、打开SSMS管理器 选择数据库 右键 然后点击还原数据库。 2、选择设备 然后点击三个点 找到本地bak文件,然后点击确定 3、点击确定,会自动弹出来一个成功的提示。...

WPF Frame 简单页面切换示例

原理比较简单&#xff0c;但是有个坑&#xff0c;为了使界面能够正确更新&#xff0c;记得使用 INotifyPropertyChanged 接口来实现属性更改通知。 <Window x:Class"PageTest.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation&…...

kafka-生产者监听器(SpringBoot整合Kafka)

文章目录 1、生产者监听器1.1、创建生产者监听器1.2、创建生产者拦截器1.3、发送消息测试1.4、使用Java代码创建主题分区副本1.5、application.yml配置----v1版1.6、屏蔽 kafka debug 日志 logback.xml1.7、引入spring-kafka依赖1.8、控制台日志 1、生产者监听器 1.1、创建生产…...

3D感知视觉表示与模型分析:深入探究视觉基础模型的三维意识

在深度学习与大规模预训练的推动下&#xff0c;视觉基础模型展现出了令人印象深刻的泛化能力。这些模型不仅能够对任意图像进行分类、分割和生成&#xff0c;而且它们的中间表示对于其他视觉任务&#xff0c;如检测和分割&#xff0c;同样具有强大的零样本能力。然而&#xff0…...

VS2019+QT5.15调用动态库dll带有命名空间

VS2019QT5.15调用动态库dll带有命名空间 vs创建动态库 参考&#xff1a; QT调用vs2019生成的c动态库-CSDN博客 demo的dll头文件&#xff1a; // 下列 ifdef 块是创建使从 DLL 导出更简单的 // 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 DLL3_EXPORTS // 符号…...

助力草莓智能自动化采摘,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建果园种植采摘场景下草莓成熟度智能检测识别系统

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到我们生活的方方面面&#xff0c;从智能家居到自动驾驶&#xff0c;再到医疗健康&#xff0c;其影响力无处不在。然而&#xff0c;当我们把目光转向中国的农业领域时&#xff0c;一个令人惊讶的…...

C++中的生成器模式

目录 生成器模式&#xff08;Builder Pattern&#xff09; 实际应用 构建一辆汽车 构建一台计算机 构建一个房子 总结 生成器模式&#xff08;Builder Pattern&#xff09; 生成器模式是一种创建型设计模式&#xff0c;它允许你分步骤创建复杂对象。与其他创建型模式不同…...

基于python的PDF文件解析器汇总

基于python的PDF文件解析器汇总 大多数已发表的科学文献目前以 PDF 格式存在&#xff0c;这是一种轻量级、普遍的文件格式&#xff0c;能够保持一致的文本布局和格式。对于人类读者而言&#xff0c; PDF格式的文件内容展示整洁且一致的布局有助于阅读&#xff0c;可以很容易地…...

C++多线程同步总结

C多线程同步总结 关于C多线程同步 一、C11规范下的线程库 1、C11 线程库的基本用法&#xff1a;创建线程、分离线程 #include<iostream> #include<thread> #include<windows.h> using namespace std; void threadProc() {cout<<"this is in t…...

【机器学习】基于CNN-RNN模型的验证码图片识别

1. 引言 1.1. OCR技术研究的背景 1.1.1. OCR技术能够提升互联网体验 随着互联网应用的广泛普及&#xff0c;用户在日常操作中频繁遇到需要输入验证码的场景&#xff0c;无论是在登录、注册、支付还是其他敏感操作中&#xff0c;验证码都扮演着重要角色来确保安全性。然而&am…...

一文读懂Samtec分离式线缆组件选型 | 快速攻略

【摘要/前言】 2023年&#xff0c;全球线缆组件市场规模大致在2100多亿美元。汽车和电信行业是线缆组件最大的两个市场&#xff0c;中国和北美是最大的两个制造地区。有趣的是&#xff0c;特定应用&#xff08;即定制&#xff09;和矩形组件是两个最大的产品组。 【Samtec产品…...

批量申请SSL证书如何做到既方便成本又最低

假如您手头拥有1千个域名&#xff0c;并且打算为每一个域名搭建网站&#xff0c;那么在当前的网络环境下&#xff0c;您必须确保这些网站通过https的方式提供服务。这意味着&#xff0c;您将为每一个域名申请SSL证书&#xff0c;以确保网站数据传输的安全性和可信度。那么&…...

Python 设计模式(创建型)

文章目录 抽象工厂模式场景示例 单例模式场景实现方式 工厂方法模式场景示例 简单工厂模式场景示例 建造者模式场景示例 原型模式场景示例 抽象工厂模式 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种将一组相关…...

PyTorch 索引与切片-Tensor基本操作

以如下 tensor a 为例&#xff0c;展示常用的 indxing, slicing 及其他高阶操作 >>> a torch.rand(4,3,28,28) >>> a.shape torch.Size([4, 3, 28, 28])Indexing: 使用索引获取目标对象&#xff0c;[x,x,x,....] >>> a[0].shape torch.Size([3, 2…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...