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[..]
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/27427.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

InfoComm 2024 直击:千视新品P3和KiloLink技术闪耀亮相

InfoComm 2024 直击:千视新品P3和KiloLink技术闪耀亮相,现场亮点不断 北京时间2024年6月13日,UTC-7时间6月12日,美国视听显示与系统集成展览会InfoComm 2024在美国拉斯维加斯正式开幕。作为全美规模最大、最具影响力的展会&#…

【Test 73 】引用 () 实际的一些用法、常引用问题 详解!

文章目录 1. 常引用的背景2. 字符 a 与 整形 97 是相同的,但是具体是怎么比较的呢 ? 1. 常引用的背景 注意: 🐧① 权限可以平移、可以缩小,但是权限 不可以放大。 🐧 类型转换中间会产生临时变量 2. 字…

[AI资讯·0612] AI测试高考物理题,最高准确率100%,OpenAI与苹果合作,将ChatGPT融入系统中,大模型在物理领域应用潜力显现

AI资讯 国产AI大战高考物理,第1题全对,第2题开始放飞终于放大招了,2024WWDC,苹果开启AI反击战苹果一夜重塑iPhone!GPT-4o加持Siri,AI深入所有APPOpenAI确认苹果集成ChatGPT 还任命了两位新高管GPT-4搞不定…

python爬虫入门:批量下载图片

引言: 爬虫也被称为网络蜘蛛(Spider),是一种自动化的软件程序,能够在互联网上漫游,按照一定的规则和算法抓取数据。 爬虫技术广泛应用于搜索引擎、 数据挖掘 、信息提取等领域,是互联网技术的重要组成部分。 摘要: 很多初学者对于一个这样新奇的事务当然愿意去探索,…

【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控

【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控 大家好 我是寸铁👊 总结了一篇【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控的文章✨ 喜欢的小伙伴…

Scrum Day盛大启幕【限时优惠】

关于 Scrum Day 智驭未来,敏捷先行 —— 2024中国Scrum大会启航 在全球数字化转型的浪潮中,敏捷已成为企业脱颖而出的关键。 Scrum中文网携手全球敏捷行业巨擘 —— Scrum.org 联袂呈现年度敏捷盛会 Scrum Day,将于今秋盛大启幕&#xff01…

Ubuntu Linux目录结构

在Linux系统中,最小的数据存储单位为文件。“一切都是文件”是Linux和UNIX一致贯彻的原则。也就是说,在Linux中,所有的数据都是以文件的形式存在的,包括设备。为了便于访问文件,Linux按照一定的层次结构来组织文件系统…

使用宝塔面板 将vue+node+mysql部署至云服务器

数据库部署 1. 导出 数据库 2. 进入宝塔面板 将数据库文件导入至宝塔面板数据库中 验证是否导入成功 点击phpMyAdmin 输入用户名密码 如果没有导入成功,可在此再导入一遍 前端项目部署 1. 将vue项目打包上传至文件 npm run build 打包成dist文件夹 压缩上传 …

解决Apache Doris占用CPU和内存过高

一、导入问题 对于 Doris 来说,一个 INSERT 命令就是一个完整的导入事务。因此不论是导入一条数据,还是多条数据,我们都不建议在生产环境使用这种方式进行数据导入。高频次的 INSERT 操作会导致在存储层产生大量的小文件,会严重影…

音视频开发-- 坑整理

1. 解码时,一定要用avcodec_parameters_to_context(),将流的参数(stream->codecpar)复制到解码器中,否则某些流可能无法正常解码。 //第七步,给给解码器上下文添加参数, avcodec_parameters_to_context(…

Linux-黑马程序员

目录 一、前言二、初识Linux1、操作系统(1)硬件和软件(2)操作系统 2、Linux3、虚拟机4、FinalShell5、WSL6、虚拟机快照 三、Linux基础命令1、Linux的目录结构2、Linux命令入门(1)Linux命令基础格式&#x…

automa学习:写一个取某东图书数据的片断

周五了,实在没事情了。正好上午有个朋友问automa的事,心想再写一个练习一下,毕竟,熟能生巧。 目标某东图书: 分析及介绍如下。 1.新建标签页 1.悬停元素。要注意 县 停 .cate_menu_item:nth-child(14) > .cate_…

VMware安装ubuntu22.04虚拟机超详细图文教程

一 、下载镜像 下载地址:Index of /ubuntu-releases/22.04.4/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 二、创建虚拟机 打开VMware点击左上角文件,创建新的虚拟机,打开后如下图: 下一步,镜像文件就是…

PostgreSQL 的内置函数

PostgreSQL 提供了大量的内置函数,这些函数可以在查询中用于处理数据、进行计算和转换。以下是一些常用的 PostgreSQL 函数: 字符串函数: concat(string1, string2, ...): 连接两个或多个字符串。 SELECT concat(first_name, , last_name) F…

深入探讨Java中的GraphQL与RESTful API设计

引言 在现代Web应用开发中,API设计是构建可扩展、高性能服务的关键。传统的RESTful API因其简单性和直观性而被广泛采用,但随着应用复杂性的增加,RESTful API在某些场景下可能显得力不从心。GraphQL作为一种新的API技术,提供了一…

如何实现跨域

如何实现跨域 当浏览器执行JS脚本时,会检测脚本要访问的协议,域名,端口号是不是和当前网址一致,不一致就是跨域。 跨域是不允许的,这种限制叫做浏览器的同源策略,简单就是浏览器不允许一个源加载脚本与其…

数据中台:生产制造产业链的“智慧大脑”!

在当今激烈竞争的生产制造领域,数据中台正扮演着至关重要的角色,它就像是产业链的“智慧大脑”,引领着产业的发展方向!数据中台在生产制造产业链、生态链中起到以下关键作用: 1. 数据整合与共享:将产业链各…

ozon如何上架产品,ozon平台怎么上架产品

在电子商务领域,产品上架是商家成功运营的关键步骤之一。对于正在或计划进军俄罗斯市场的卖家来说,了解如何在Ozon平台高效上架产品至关重要。接下来讲解下ozon如何上架产品,ozon平台怎么上架产品! 产品上架工具:D.DDq…

神经网络学习1—nn.Module

nn.module 为所有神经网络提供了一个模板 import torch.nn as nn import torch.nn.functional as Fclass Model(nn.Module):def __init__(self):super(Model, self).__init__()self.conv1 nn.Conv2d(1, 20, 5)self.conv2 nn.Conv2d(20, 20, 5)def forward(self, x):x F.rel…

Kettle 传参(参数)的使用

Kettle 传参的符号是 ? 。 一、给表改名,并在名称后面加上日期 1、表输入获取名称参数 我这是通过SQL来获取 SELECT concat("score","_",DATE_FORMAT(sysdate(),%Y%m%d%H%i)) aa FROM dual2、执行SQL语句 使用SQL脚本组件 想要获得参数&a…