rust变量绑定、拷贝、转移、引用

目录

一,clone、copy

1,基本类型

2,类型的clone特征

3,显式声明结构体的clone特征

4,类型的copy特征

5,显式声明结构体的clone特征

5,变量和字面量的特征

6,特征总结

二,变量绑定

1,clone拷贝场景

2,copy拷贝场景

3,所有权转移场景

4,转移的永久性

三,引用

1,对常量的引用

2,对变量的不可变引用

3,对变量的可变引用

5,函数调用

四,引用总结

1,引用的生命周期

2,对字面量的引用

3,对普通变量的引用

4,对引用变量的引用

5,对同一变量的引用

6,链式引用


一,clone、copy

1,基本类型

rust基本类型包括:

  • 所有整数类型,比如 u32
  • 布尔类型,bool,它的值是 true 和 false
  • 所有浮点数类型,比如 f64
  • 字符类型,char

2,类型的clone特征

拥有clone特征的类型:

  • 基本类型
  • String
  • 容器
  • 显式声明clone特征的结构体

没有clone特征的类型:

  • 没有显式声明clone特征的结构体(结构体默认)

递归决定是否有clone特征的类型:

  • 元组,当且仅当其包含的类型都有clone特征的情况下,其自身有clone特征。

3,显式声明结构体的clone特征

前提条件:当且仅当结构体中的成员都具有clone特征的情况下,可以显式声明clone特征。

#[derive(Clone)]
struct S{}

#[derive(Clone)]
struct P{
    a:i32,
    b:S,
}

4,类型的copy特征

拥有copy特征的类型:

  • 基本类型
  • 显式声明clone特征的结构体

没有copy特征的类型:

  • String
  • 容器
  • 没有显式声明clone特征的结构体(结构体默认)

递归决定是否有copy特征的类型:

  • 元组,当且仅当其包含的类型都有copy特征的情况下,其自身有copy特征。

5,显式声明结构体的clone特征

前提条件:结构体具有clone特征

#[derive(Clone,Copy)]
struct P{
    a:i32,
}

fn main() {
    let x:P=P{a:5};
    let y=x;
    assert_eq!(x.a,5);
}

5,变量和字面量的特征

字面量会自动推导出类型,所以变量和字面量都有唯一确定的类型。

变量和字面量是否具有clone和copy特征,完全取决于其类型是否具有。

6,特征总结

所有类型可以分为3类:

没有clone和copy特征,有clone没有copy特征,有clone和copy特征。

二,变量绑定

1,clone拷贝场景

对于有clone特征的变量或字面量,可以调用clone函数进行拷贝而不转移所有权。

#[derive(Clone)]
struct P{
    a:i32,
}

fn main() {
    let x:P=P{a:5};
    let y=x.clone();
    assert_eq!(x.a,5);
}

2,copy拷贝场景

如果let绑定语句的等号右边是一个有copy特征的变量或字面量,那么这是一个拷贝行为。

    let x = 5;
    let xx = x;
    assert_eq!(5, x);
    assert_eq!(6, xx+1);

3,所有权转移场景

如果let绑定语句的等号右边是一个没有copy特征的变量或字面量,那么这是一个所有权转移的行为。

错误代码:

    let x = vec![1,2,3];
    assert_eq!(x[0],1);
    let y=x;
    assert_eq!(x[0],1); // 错误

错误原因:y转移走了所有权,不能再使用x

4,转移的永久性

错误代码:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:5};
    {
        let y= x;
    }
    x.a=6;
    println!("end");
}

错误原因:y转移了x的所有权之后,x就再也不能用了,即使y的生命周期结束了也一样。

三,引用

1,对常量的引用

fn main() {
    let x:P=P{a:6};
    let y= & x;
    assert_eq!(x.a,6);
    assert_eq!(y.a,6);
    assert_eq!((*y).a,6);
    println!("end");
}

常量只有可读性,原变量x和引用变量y都持有读的能力。

这里y可以直接用,也可以先解引用再用。

2,对变量的不可变引用

正确代码:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:6};
    let y= &x;
    assert_eq!(x.a,6);
    assert_eq!(y.a,6);
    assert_eq!((*y).a,6);
    x.a=5;
    assert_eq!(x.a,5);
    println!("end");
}

变量x持有读写能力,不可变的引用y只有读能力。

错误代码:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:6};
    let y= &x;
    x.a=5;
    assert_eq!(y.a,5);
    println!("end");
}

错误原因:在y的读行为结束之前,x不能执行写行为,否则会造成冲突

同一个变量可以引用多次,也可以对引用变量再进行引用:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:6};
    let y= &x;
    let z=&x;
    let z2=&z;
    let z3=&z2;
    let z4=&z3;
    assert_eq!(x.a,6);
    assert_eq!(y.a,6);
    assert_eq!(z.a,6);
    assert_eq!(z4.a,6);
    assert_eq!((*z4).a,6);
    assert_eq!((**z4).a,6);
    assert_eq!((***z4).a,6);
    assert_eq!((****z4).a,6);
    println!("end");
}

这里的z4可以直接读成员,也可以解引用若干次再使用。

3,对变量的可变引用

正确代码:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:6};
    let y= &mut x;
    assert_eq!(y.a,6);
    y.a=5;
    assert_eq!(x.a,5);
    println!("end");
}

错误代码:

struct P{
    a:i32,
}
fn main() {
    let mut x:P=P{a:6};
    let y= &mut x;
    assert_eq!(x.a,6);
    assert_eq!(y.a,6);    
    println!("end");
}

错误原因:y的读写行为结束之前,x不能执行读行为,否则会造成冲突

可变引用和不可变引用不能同时存在,否则会造成冲突。

5,函数调用

错误代码:

fn fun(x:Vec<i32>)->i32{
    x[0]+1
}

fn main() {
    let x = vec![1,2,3];
    assert_eq!(fun(x),2);
    assert_eq!(x.len(), 3);
    println!("end");
}

错误原因:函数调用时转移走了所有权。

正确代码:

fn fun(x:&Vec<i32>)->i32{
    x[0]+1
}

fn main() {
    let x = vec![1,2,3];
    assert_eq!(fun(&x),2);
    assert_eq!(x.len(), 3);
    println!("end");
}

实现方式:函数入参改成引用类型,传参时也要改成引用。

四,引用总结

1,引用的生命周期

(1)一个引用变量的声明周期只到它的最后一次读写为止

(2)如果声明了引用之后没有读写,那么生命周期直接结束,但是这和直接删除这一句不一样,因为声明引用这一行相当于一次读操作

(3)如果一个引用变量y被z引用了,且z最后一次读写比y的最后一次读写更晚,那么y的生命周期延长到z的最后一次读写。

PS:如果声明了z是对y的引用之后没有读写,那么声明的这一句就是z的最后一次读操作,这也可能延长y的声明周期。

讨论引用规则时我们默认只讨论一个生命周期之内的引用

2,对字面量的引用

对字面量的引用,无论是可变引用还有不可变引用,其实都不是引用,而是copy拷贝,讨论引用规则时我们默认不把对字面量的引用这个当做引用

3,对普通变量的引用

对于普通变量,有mut的是可变变量,没有mut的是不可变变量(常量)。

可变变量可以加可变引用,也可以加不可变引用,不可变变量只能加不可变引用

4,对引用变量的引用

无论是可变引用变量还是不可变引用变量,都和普通变量一样,可能是可变变量也可能是不可能变量

对引用变量加引用的规则,和对普通变量一致。

5,对同一变量的引用

对不可变变量不能加可变引用,可以加多个不可变引用。

对可变变量可以加唯一的可变引用,也可以加多个不可变引用。

即,可变引用存在的情况下,只能有一个引用。

6,链式引用

以y是对x的引用,z是对y的引用为例,更长的链的情况应该规则类似。

y的声明周期参考上文“引用的生命周期”。

在所有情况下,z对x的读写能力都和y对x的读写能力相同,因为z一直持有对y的读能力

(1)x是不可变变量

x和y 一直有读能力,没有写能力

(2)x是可变变量

在y的最后一次读操作或写操作之前,x没有读写能力,之后,x有读写能力

y的能力在声明周期内不变,有读能力,有没有写能力取决于是可变引用还是不可变引用。

五,ref

当我们要引用一个Option的内部成员,可以用ref

struct P{
    a:i32,
}
struct Node{
    x:Option<P>,
}
fn main() {
    let mut p = Node{x:Some(P{a:1})};
    if let Some(ref mut x)=p.x{
        x.a=2;
    }
    if let Some( x)=p.x{
        assert_eq!(x.a,2);
    }
    println!("end");
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

技术分享 | 抓包分析 TCP 协议

TCP 协议是在传输层中&#xff0c;一种面向连接的、可靠的、基于字节流的传输层通信协议。 环境准备 对接口测试工具进行分类&#xff0c;可以如下几类&#xff1a; 网络嗅探工具&#xff1a;tcpdump&#xff0c;wireshark代理工具&#xff1a;fiddler&#xff0c;charles&a…

触摸屏通过modbus转profinet网关连接PLC与变频器485modbus通讯案例

通过兴达易控modbus转profinet网关&#xff08;XD-MDPN100&#xff09;的桥接&#xff0c;数据可以以高速、可靠的方式从触摸屏传递到PLC&#xff0c;同时能够实现PLC对变频器的监控和控制。这四台变频器通过485modbus协议与PLC通讯&#xff0c;使得系统能够实现对变频器的高效…

ACmix:卷积和self-attention的结合,YOLOv5改进之ACmix

目录 一、ACmix理论部分 二、代码 三、YOLOv5改进 ACC3 一、ACmix理论部分 论文地址:2111.14556.pdf (arxi

梳理自动驾驶中的各类坐标系

目录 自动驾驶中的坐标系定义 关于坐标系的定义 几大常用坐标系 世界坐标系 自车坐标系 传感器坐标系 激光雷达坐标系 相机坐标系 如何理解坐标转换 机器人基础中的坐标转换概念 左乘右乘的概念 对左乘右乘的理解 再谈自动驾驶中的坐标转换 本节参考文献 自动驾驶…

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较

517-0224-16A-458525 531X303MCPARG1 现代工厂中DCS与PLC的比较 分布式控制系统(DCSs)和可编程逻辑控制器(PLC)之间的区别可以归结为一个简单的足球比喻。你的指挥系统是你的船长。团队名单上的第一个名字&#xff0c;你的DCS是可靠的&#xff0c;勤奋的&#xff0c;控制着整个…

django+drf+vue 简单系统搭建 (1) - django创建项目

本系列文章为了记录自己第一个系统生成过程&#xff0c;主要使用django,drf,vue。本人非专业人士&#xff0c;此文只为记录学习&#xff0c;若有部分描述不够准确的地方&#xff0c;烦请指正。 建立这个系统的原因是因为&#xff0c;在生活中&#xff0c;很多觉得可以一两行代码…

麒麟信安加入“工业操作系统创新伙伴计划”,并亮相2023第三届工控中国大会新品发布会

11月1日-3日&#xff0c;2023第三届工控中国大会在苏州太湖国际会议中心举办。本届大会以“生态链接 智控未来 筑基新型工业化”为主题&#xff0c;由中国电子信息产业发展研究院、中国工业经济联合会、国家智能制造专家委员会、国家产业基础专家委员会、江苏省工业和信息化厅、…

基于单片机的车载太阳能板自动跟踪系统研究

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、总体设计开发流程二、机械结构设计与研究3.1 机械系统总体设计3.1.1 太阳能板折叠传动 三、太阳能自动跟踪系统硬…

[C语言趣编程]抓小偷问题

1问题&#xff1a; 2解题思路&#xff1a; 可以利用数值的思想&#xff0c;因为已经知道4人有3人说真话&#xff0c;所以让每条语句的真假当作1和0&#xff0c;最终结果为3&#xff0c;利用循环自动判断出谁是小偷&#xff1b; 3运行代码&#xff1a; #include<stdio.h&g…

操作系统:银行家算法

文章目录 银行家算法一、实验目的二、实验要求与内容、过程与结果 系列文章 银行家算法 一、实验目的 1、理解银行家算法。 2、掌握进程安全性检查的方法及资源分配方法。 二、实验要求与内容、过程与结果 1、将图5-1补充完整&#xff0c;画出银行家算法的流程图。 图5-1 银…

web —— html

Web —— css基础 1. HTML2. 基本HTML结构3. HTML常用标签3.1 文本相关标签3.2 HTML图像标签3.3 HTML超链接标签3.4 HTML表&#xff0c;单3.4.1 HTML表格3.4.2 HTML表单&#xff0c;输入框&#xff08;多选框&#xff0c;单选框&#xff09;下拉框 3.5 HTML分区标签3.5.1 div标…

k8s-----数据存储

目录 一、数据存储的概念 二、基本存储 1、EmptyDir存储卷 2、hostPath存储卷 3、nfs共享存储卷 三、高级存储 1、PV&#xff08;持久化卷&#xff09; 2、PVC&#xff08;持久化卷声明&#xff09; 3、静态PV实验 4、动态PV实验 4.1 在stor01节点上安装nfs&#xf…

肩颈筋膜炎怎么治疗才能彻底除根

肌筋膜炎是肩背部肩胛骨内侧某一点的疼痛&#xff0c;同时可以放射到同侧的肩部以及上肢的疼痛&#xff0c;肩关节活动的受限以及同侧肢体麻木&#xff0c;无力的症状。 在肩关节劳累或者在着凉时可以诱发&#xff0c;主要表现为肩后背部明显疼痛&#xff0c;肩关节抬举以及向各…

华为李鹏:到 2025 年智能算力需求将达到目前水平的 100 倍

在第十四届全球移动宽带论坛上&#xff0c;华为高级副总裁、运营商 BG 总裁李鹏表示&#xff0c;大模型为代表的 AI 应用发展带来对智能算力的爆发式需求。 李鹏在题为《加速 5G 商业正循环&#xff0c;拥抱更繁荣的 5.5G》的讲话中表示&#xff0c;「5G 已经走在商业成功的正确…

度假胜地:色彩、曲线与艺术之家

葡萄牙&#xff0c;这里的建筑风格是非常独特的&#xff0c;而不是当地传统的白色房屋&#xff0c;充满了粉红和蓝色的色彩&#xff0c;以及一些印度和巴西的灵感。 在当地&#xff0c;有一座混凝土建筑&#xff0c;它建在通往大海的道路上&#xff0c;建筑的设计理念使其更适合…

volatile-日常使用场景

6.4 如何正确使用volatile 单一赋值可以&#xff0c;但是含复合运算赋值不可以&#xff08;i之类的&#xff09; volatile int a 10; volatile boolean flag true; 状态标志&#xff0c;判断业务是否结束 作为一个布尔状态标志&#xff0c;用于指示发生了一个重要的一次…

el-checkbox-group的全选与反选

需求如下&#xff1a; 思路&#xff1a;在点击全部时按钮组双向绑定赋值全部值&#xff0c;点击按钮组内按钮计算选中按钮数量与按钮组数量对比&#xff0c;判定是否选中全部 代码如下&#xff1a; <template><div><el-checkbox-button v-model"checkall…

golang工程中间件——redis常用结构及应用(string, hash, list)

Redis 命令中心 【golang工程中间件——redisxxxxx】这些篇文章专门以应用为主&#xff0c;原理性的后续博主复习到的时候再详细阐述 string结构以及应用 字符数组&#xff0c;redis字符串是二进制安全字符串&#xff0c;可以存储图片等二进制数据&#xff0c;同时也可以存…

Spark 新特性+核心回顾

Spark 新特性核心 本文来自 B站 黑马程序员 - Spark教程 &#xff1a;原地址 1. 掌握Spark的Shuffle流程 1.1 Spark Shuffle Map和Reduce 在Shuffle过程中&#xff0c;提供数据的称之为Map端&#xff08;Shuffle Write&#xff09;接收数据的称之为Reduce端&#xff08;Sh…

10 索引优化与查询优化

文章目录 索引失效案例关联查询优化对于左外连接对于内连接JOIN语句原理简单嵌套循环连接SNLJ索引嵌套循环连接INLJ块嵌套循环连接BNLJHash Join 子查询优化排序优化filesort算法&#xff1a;双路排序和单路排序 分组优化分页优化优先考虑覆盖索引索引下推ICP使用条件 其他查询…