当前位置: 首页 > 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…...

SEO_从零开始,手把手教你制定SEO优化方案(216 )

SEO:从零开始&#xff0c;手把手教你制定SEO优化方案 在当今互联网时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已经成为任何网站希望获得高流量和高曝光的关键。对于新手来说&#xff0c;SEO可能看起来复杂且充满谜团。本文将从零开始&#xff0c;手把手教你如何…...

NaViL-9B图文对话教程:上传图片即问即答,新手零基础快速上手

NaViL-9B图文对话教程&#xff1a;上传图片即问即答&#xff0c;新手零基础快速上手 1. 认识NaViL-9B&#xff1a;你的智能图文助手 NaViL-9B是一款强大的多模态大语言模型&#xff0c;它能同时理解文字和图片内容。想象一下&#xff0c;你有一个既能聊天又能"看"图…...

PLC编程必备:西门子200SMART符号表与注释的高效使用技巧

PLC编程效率革命&#xff1a;西门子200SMART符号表与注释的进阶实践 在工业自动化领域&#xff0c;PLC编程的可读性和可维护性往往决定了项目的长期成败。许多工程师花费大量时间编写功能代码&#xff0c;却忽视了符号表和注释这一"软实力"的建设。当项目需要升级或故…...

Llama-3.2V-11B-cot实战教程:Streamlit界面响应延迟优化与调试

Llama-3.2V-11B-cot实战教程&#xff1a;Streamlit界面响应延迟优化与调试 1. 项目背景与问题定位 Llama-3.2V-11B-cot作为新一代多模态大模型&#xff0c;在视觉推理任务中展现出强大的能力。但在实际使用Streamlit构建交互界面时&#xff0c;用户常会遇到响应延迟的问题。本…...

拆解国产4mm量子随机数芯片:从VCSEL激光器到PIN探测器的保姆级工作流程

国产4mm量子随机数芯片全链路解析&#xff1a;从VCSEL驱动到信号处理的工程实现 量子随机数生成器&#xff08;QRNG&#xff09;作为信息安全的基础设施&#xff0c;其核心价值在于利用量子力学原理实现不可预测的真随机性。本文将聚焦国产4mm尺寸QRNG芯片的实现细节&#xff0…...

从71.5%到87.5%:我是如何用PyTorch+ResNeXt101优化GTZAN音乐分类精度的(附完整代码)

从71.5%到87.5%&#xff1a;PyTorch音乐分类模型优化实战全解析 音乐分类任务一直是音频处理领域的热门研究方向。在GTZAN数据集上&#xff0c;我们经常会遇到基础模型表现不佳的问题——比如使用ResNet18时验证集准确率仅能达到71.5%。本文将详细分享如何通过一系列优化策略&a…...

**InfluxDB + Python 实战:从时序数据采集到可视化监控的完整流水线构

InfluxDB Python 实战&#xff1a;从时序数据采集到可视化监控的完整流水线构建 在现代微服务架构和物联网&#xff08;IoT&#xff09;场景中&#xff0c;高效、稳定地存储与分析时间序列数据已成为系统可观测性的核心。作为专为时序数据优化的数据库&#xff0c;InfluxDB 凭…...

王道C语言督学营课后习题OJ题解:手把手教你如何高效刷题

王道C语言OJ题解实战指南&#xff1a;从刷题到精通的系统化路径 在编程学习的道路上&#xff0c;OJ&#xff08;Online Judge&#xff09;系统就像一位严格的考官&#xff0c;它能准确检验我们对C语言的理解深度和算法应用能力。很多学习者虽然掌握了基础语法&#xff0c;却在面…...

Sqoop --merge-key参数深度解析:增量数据合并的终极利器

Sqoop --merge-key参数深度解析&#xff1a;增量数据合并的终极利器引言1. --merge-key参数概述1.1 基本概念1.2 为什么需要--merge-key&#xff1f;2. --merge-key的工作原理2.1 执行流程2.2 数据合并逻辑3. 使用场景详解3.1 场景一&#xff1a;lastmodified模式下的自动合并3…...

SDMatte前端面试题实战:如何实现一个高性能的图片上传与预览组件

SDMatte前端面试题实战&#xff1a;如何实现一个高性能的图片上传与预览组件 1. 场景需求与技术挑战 在电商、设计平台等实际业务中&#xff0c;图片上传与处理是高频核心功能。以SDMatte智能抠图工具为例&#xff0c;用户需要上传产品图片进行背景去除&#xff0c;但面临几个…...