Rust 运算符快速了解

news2024/11/17 1:30:41

【图书介绍】《Rust编程与项目实战》-CSDN博客

《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com)

Rust编程与项目实战_夏天又到了的博客-CSDN博客

4.1  运  算  符

前面已经学习了变量和常量,本节开始对它们进行操作,这就要用到Rust的操作符(Operator)。操作符通常是由一个或多个特殊的符号组成的(也有非特殊符号的操作符,如as),比如+、−、*、/、%、&、*等。每个操作符都代表一种动作(或操作),这种动作作用于操作数之上。简单来说,就是对操作数执行某种操作,然后返回操作后得到的结果。比如,加法操作3 + 2,这里的+是操作符,加号两边的3和2是操作数,加法符号的作用是对操作数3加上操作数2,得到计算结果5并返回5。

有些语言,很多操作符都是关键字,比如add、equals等。Rust的操作符主要是由符号组成的,比如+、−等。这些符号不在字母表中,但是在所有键盘上都可以找到。这个特点使得Rust程序更简洁,也更国际化。运算符也称操作符。运算符是Rust语言的基础,所以非常重要。

4.1.1  赋值运算符

赋值运算符的功能是将一个值赋给一个变量。比如:

a = 5;

以上代码将整数5赋给变量a。= 运算符左边的部分叫作左值(lvalue,left value),右边的部分叫作右值(rvalue,right value)。左值必须是一个变量,而右值可以是一个常量、一个变量、一个运算的结果,或者是前面几项的任意组合。

有必要强调赋值运算符永远是将右边的值赋给左边,不会反过来。比如:

a = b;

以上代码将变量b的值赋给变量a,不论赋值前a存储的是什么值,这行代码执行后,a的值就和b的值一样了。但要注意,我们只是将b的值赋给a,以后如果b的值改变了,并不会影响a的值。下面来看实例。

【例4.1】  赋值运算符的使用

   在命令行下用命令cargo new myrust新建一个Rust项目,项目名是myrust。

   打开VS Code,再打开文件夹myrust,然后在VS Code中打开src下的main.rs,输入如下    代码:

fn main() {
    let mut a:i32;
    let mut b:i32;            //此时a、b的值未知
    a = 10;                     // a:10,b未知
    b = 4;                      // a:10,b:4
    a = b;                      // a:4,b:4
    b = 7;                      // a:4,b:7
    println!("{},{}",a,b);
}

以上代码的结果是,a的值为4,b的值为7。最后一行中b的值被改变并不会影响a,虽然在此之前我们声明了a = b;(从右到左规则,right-to-left rule)。

   运行结果如下:

4,7

Rust语言支持5种数学运算符,分别为加(+)、减(−)、乘(*)、除(/)、取模(%),括号里的符号就是数学运算符号。加减乘除运算想必大家都很了解,它们和一般的数学运算符没有区别。

唯一你可能不太熟悉的是用百分号(%)表示的取模运算(Module)。取模运算是取两个整数相除的余数。例如,如果我们写a = 11 % 3;,变量a的值将会为2,因为2是11除以3的余数。比如:

fn main() {
    let mut a:i32;
    let mut b:i32;
    let mut c:i32; 
    a = 11 % 3;                // 取模运算得a为2
    b = 4+a;                    //加法运算得b为6
    c =(a+b)/2;                //除法运算得c为4       
    println!("{},{},{}",a,b,c);
}

输出结果:

2,6,4

4.1.3  组合运算符

Rust以书写简练著称,其一大特色就是这些组合运算符(+=、−=、*=、/=及其他),这些运算符使得只用一个基本运算符就可以改写变量的值:

value += increase; 等同于 value = value + increase;

比如:

  • a −= 5; 等同于 a = a − 5;。
  • a /= b; 等同于 a = a / b;。
  • price *= units + 1; 等同于price = price * (units + 1);。

其他运算符以此类推。下面来看一个组合运算符的例子,代码如下:

fn main() {
    let mut a:i32;
    let mut b:i32;
    let mut c:i32; 
    a = 11 % 3;         // a:2
    b = 4+a;            // b:6
    c =(a+b)/2;  //c:3  
    a+=c;  
    b*=a;
    c/=2;   
    println!("{},{},{}",a,b,c);
}

结果输出:

6,6,4

值得庆幸的是,Rust 语言不支持自增运算符(++)和自减运算符(--),因此本节绝对不会出现类似于a+++++i这样让人血压升高的语句。其实,编程语言由于是给人用的,一定要考虑到人的局限性(就是面对复杂事物容易出错),所以编程语言一定要简单明了,Rust去掉了++和--,相对于C语言而言,绝对是个进步,可以从源头上尽可能防止人类出错。

4.1.4  关系运算符

我们用关系运算符来比较两个表达式,关系运算的结果是一个布尔值,即它的值只能是true或false。例如,我们想通过比较两个表达式来看它们是否相等,或一个值是否比另一个值大。表4-1所示为Rust的关系运算符。

表4-1  Rust的关系运算符

关系运算符

   

==

如果左右值相等,则运算符结果是true,否则是false

!=

如果左右值不相等,则运算符结果是true,否则是false

>

如果左值大于右值,则运算符结果是true,否则是false

<

如果左值小于右值,则运算符结果是true,否则是false

>=

如果左值大于或等于右值,则运算符结果是true,否则是false

<=

如果左值小于或等于右值,则运算符结果是true,否则是false

示例代码如下:

fn main() {
    let mut a:bool;
    let mut b:bool;
    let mut c:bool;
    a=(7!=5);
    b = (100<=99);
    c=(6==6);
    println!("{},{},{}",a,b,c);
}

运行结果:

rue,false,true

除使用数字常量外,我们也可以使用任何有效表达式,包括变量。比如下列代码:

fn main() {
    let mut a:i32;
    let mut b:i32;
    let mut c:i32;
    a=2;
    b=3;
    c=6;
    println!("{},{},{}",(a == 5),(a*b >= c),(b+4 > a*c));
}

输出结果:false,true,false。(a*b >= c)返回true是因为它实际是(2*3 >= 6),(b+4 > a*c)返回false因为它实际是(3+4 > 2*6)。

值得注意的是,运算符=(单个等号)不同于运算符==(两个等号),前者是赋值运算符(将等号右边的表达式值赋给左边的变量);后者(==)是一个判断等于的关系运算符,用来判断运算符两边的表达式是否相等。

4.1.5  逻辑运算符

运算符!等同于boolean运算NOT(取非),它只有一个操作数(Operand),写在它的右边。它做的唯一工作就是取该操作数的反面值,也就是说如果操作数值为真(true),那么运算后值变为假(false),如果操作数值为假(false),则运算结果为真(true)。它就好像是取与操作数相反的值。例如:

  • !(5 == 5)返回false,因为它右边的表达式(5 == 5)为真(true)。
  • !(6 <= 4)返回true,因为(6 <= 4)为假(false)。
  • !true返回假(false)。
  • !false返回真(true)。

大家如果不信,可以用下列代码直接输出看看结果:

println!("{},{},{},{}",!(5 == 5),!(6 <= 4),!true,!false);

逻辑运算符&&和||用来计算两个表达式而获得一个结果值。它们分别对应逻辑运算中的与运算(AND)和或运算(OR)。它们的运算结果取决于两个操作数的关系,如表4-2所示。

表4-2  两个操作数的逻辑运(&&和||)

第一个操作数a

第二个操作数b

a && b结果

a || b结果

true

true

true

true

true

false

false

true

false

true

false

true

false

false

false

false

例如:

  • ( (5 == 5) && (3 > 6) )返回false ( true && false )。
  • ( (5 == 5) || (3 > 6))返回true ( true || false )。

大家如果不信,可以用下列代码直接输出看看结果:

println!("{},{}",( (5 == 5) && (3 > 6) ) ,( (5 == 5) || (3 > 6)));

4.1.6  位运算符

位运算符以比特位改写变量存储的数值,也就是改写变量值的二进制表示。Rust的位运算符如表4-3所示。

表4-3  Rust的位运算符

   

   

   

   

位与

&

若相同位都是1,则返回1;否则返回 0

(A & B) 结果为2

位或

|

若相同位只有一个是1,则返回1;否则返回 0

(A | B) 结果为3

异或

^

若相同位不相同,则返回1;否则返回 0

(A ^ B) 结果为1

位非

!

把位中的1换成0,0换成1

(!B) 结果为−4

左移

<<

操作数中的所有位向左移动指定位数,右边的位补 0

(A << 1) 结果为4

右移

>>

操作数中的所有位向右移动指定位数,左边的位补 0

(A >> 1) 结果为1

下面的范例演示上面提到的所有位运算符。

fn main() {

    let a:i32 = 2;     // 二进制表示为 0 0 0 0 0 0 1 0
    let b:i32 = 3;     // 二进制表示为 0 0 0 0 0 0 1 1

    let mut result:i32;

    result = a & b;
    println!("(a & b) => {} ",result);

    result = a | b;
    println!("(a | b) => {} ",result) ;

    result = a ^ b;
    println!("(a ^ b) => {} ",result);

    result = !b;
    println!("(!b) => {} ",result);

    result = a << b;
    println!("(a << b) => {}",result);

    result = a >> b;
    println!("(a >> b) => {}",result);

}

输出结果如下:

(a & b) => 2
(a | b) => 3
(a ^ b) => 1
(!b) => -4
(a << b) => 16
(a >> b) => 0

4.1.7  变量类型转换运算符

变量类型转换运算符可以将一种类型的数据转换为另一种类型的数据。在Rust中,可以使用关键字as进行类型转换,as 运算符有点像C中的强制类型转换,区别在于,它只能用于原始类型(i32、i64、f32、f64、u8、u32、char等类型),并且它是安全的。注意,不同的数值类型是不能进行隐式转换的。比如:

let b: i64 = iNum;  //iNum是一个i32类型的变量

会出现编译错误,提示无法进行类型转换。这时可以使用as 进行转换,比如:

fn main() {

    let mut iNum:i32;     
    let mut b:i64;    

    iNum=100;
    b = iNum as i64;
    print!("{}",b);

}

输出结果:100。

为什么as是安全的?尝试以下代码:

b = iNum as char;

编译器报错:

error[E0604]: only `u8` can be cast as `char`, not `i32`

可见在不相关的类型之间,Rust 会拒绝转换,这样避免了运行时错误。

4.1.8  运算符的优先级

当多个操作数组成复杂的表达式时,我们可能会疑惑哪个运算先被计算,哪个后被计算。例如以下表达式:

a = 5 + 7 % 2

我们可以怀疑它实际上表示:a = 5 + (7 % 2) 结果为6,还是 a = (5 + 7) % 2 结果为0?

正确答案为第一个,结果为6。每一个运算符都有一个固定的优先级,不仅是数学运算符(我们可能在学习数学的时候已经很了解它们的优先顺序了),所有在Rust中出现的运算符都有优先级。从最高级到最低级,运算符的优先级按表4-4排列。

表4-4  运算符的优先级

   

   

结合方向

1

一元操作符(!、&、&mut)

从左到右

2

二元操作符(*、/、%)

从左到右

3

二元操作符(+、−)

从左到右

4

位移计算(<<、>>)

从左到右

5

位操作(&)

从左到右

6

位操作(|)

从左到右

7

比较操作(==、!=、<、>、<=、>=)

需要括号

8

逻辑与(&&)

从左到右

9

逻辑或(||)

从左到右

10

赋值操作(=、+=、−=、/=、%=、|=、^=、<<=、>>=)

从右到左

以下是简单的示例:

fn main() {

    //二元计算操作
    println!("1 + 2 = {}", 1u32 + 2);
    println!("1 - 2 = {}", 1i32 - 2);

    //逻辑操作
    println!("true AND false is {}", true && false);
    println!("true OR false is {}", true || false);
    println!("NOT true is {}", !true);

    //位运算操作
    println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
    println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
    println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
    println!("1 << 5 is {}", 1u32 << 5);
    println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);

}

运行结果如下:

1 + 2 = 3
1 - 2 = -1
true AND false is false
true OR false is true
NOT true is false
0011 AND 0101 is 0001
0011 OR 0101 is 0111
0011 XOR 0101 is 0110
1 << 5 is 32
0x80 >> 2 is 0x20

所有这些运算符的优先级顺序可以通过使用一对圆括号“()”来控制,而且更易读懂,示例如下:

a = 5 + 7 % 2;

根据我们想要实现的计算不同,可以写成:

a = 5 + (7 % 2);

效果和a = 5 + 7 % 2;一样,因为%的优先级比+高,所以加不加括号没什么区别。如果要先计算5+7,则可以这样:

a = (5 + 7) % 2;

此时最终计算结果就不同了。所以如果想写一个复杂的表达式而不敢肯定各个运算的执行顺序,那么就加上括号。这样可以使代码更易读懂。

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

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

相关文章

java之单链表的基本概念及创建

1.链表的概念: 链表是一种 物理存储结构上非连续 存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。 组成结构: 由一系列节点组成&#xff0c;每个节点包含数据域和指向下一个节点的指针。 优点: 动态大小&#xff0c;易于插入和删除操作。 缺点…

【网络安全 | 靶机搭建】修改镜像源、更新软件源、安装git、更改python版本等

文章目录 0x00、必要准备0x01、修改镜像源0x02、更新软件源并清除缓存0x03、安装git0x04、更改默认Python版本为python30x05、安装增强功能0x06、vmware虚拟机导出iso0x00、必要准备 安装虚拟机时必须保存用户名、密码,用于后续操作,可以截图保存: 以下内容按个人需要进行配…

如何将生物序列tokenization为token?

原理讲解 tokenization是自然语言处理领域非常成熟的一项技术&#xff0c;tokenization就是把我们研究的语言转换成计算机能够识别的数字——token。 在生物领域&#xff0c;如何把核苷酸或氨基酸序列tokenization成token呢&#xff1f; 我们可以使用k-mer技术&#xff1a; k-m…

GDPU Andriod移动应用 Activity

移动应用开发入门级必看&#xff0c;用活动打造属于你的页面。 重要的更新公告 &#xff01;&#xff01;&#xff01;GDPU的小伙伴&#xff0c;感谢大家的支持&#xff0c;希望到此一游的帅哥美女能有所帮助。本学期的前端框架及移动应用&#xff0c;采用专栏订阅量达到50才开…

医院伤员小程序点餐———未来之窗行业应用跨平台架构

一、读取服务器医院信息 var 未来之窗人工智-商家信息-医院职工 {//2024-09-22 cyber_getMerchant_CardUser_V20240922: function(appikkey,merchant_id,store_id,ecogen_sponsor_appid,openid,frommsg,wlzc_callback) {//2023-7-6 里程碑var wlzcapi"加入url";wx.re…

深度学习自编码器 - 去噪自编码器篇

序言 在深度学习的广阔天地中&#xff0c;自编码器作为一种强大的无监督学习工具&#xff0c;通过重构输入数据的方式&#xff0c;不仅实现了数据的有效压缩&#xff0c;还探索了数据的内在表示。而去噪自编码器&#xff08; Denoising Autoencoder, DAE \text{Denoising Auto…

ES6 -- 2015

学习视频 1. let和const 1.1 let 变量必须先声明再使用同一变量不能重复声明变量有块级作用域 1.2 const 声明常量&#xff0c;常量不能改变常量必须有初始值&#xff0c;不能先声明再赋值 2. 解构 1 数组解构 保持左右的结构一样&#xff0c;安装顺序一一对应 完全解构…

CVE-2024-46101

前言 自己挖的第一个CVE~ 喜提critical 这里简单说一下。 漏洞简介 GDidees CMS < 3.9.1 的版本&#xff0c;存在一个任意文件上传漏洞。允许登录后的攻击者上传webshell获得网站的权限。 影响版本&#xff1a; GDidees CMS < 3.9.1 &#xff08;其它的我没测。。&am…

日志系统扩展二:日志服务器的实现

日志系统扩展二&#xff1a;日志服务器的实现 一、设计1.为何要这么扩展&#xff1f;2.应用层协议的选择1.HTTP&#xff1f;2.自定义应用层协议 二、自定义应用层协议的实现1.声明日志器1.服务器和客户端这里日志器的关联2.枚举类型的定义3.sinks数组的定义 2.打印日志1.logMes…

MySQL record 06 part

事务、存储过程 事务&#xff1a; MySQL的同步&#xff0c;同步是指 together done&#xff0c;要么一起前进&#xff0c;要么一起后退的意思。 注意&#xff0c;回滚 rollback 对已经提交 commit 的数据是无效的&#xff0c;也就是说&#xff0c;只能对没有被提交 commit …

CSS 布局三大样式简单学习

目录 1. css 浮动 1.1 效果1 1.2 效果2 1.3 效果3 1.4 效果4 2. css 定位 2.1 absolute 2.2 relative 2.3 fixed 3. css 盒子模型 3.1 效果1 3.2 效果2 3.3 效果3 3.4 效果4 1. css 浮动 1.1 效果1 1.2 效果2 1.3 效果3 1.4 效果4 2. css 定位 2.1 absolute 2.2 …

thinkphp 做分布式服务+读写分离+分库分表(分区)(后续接着写)

thinkphp 做分布式服务读写分离分库分表&#xff08;分区&#xff09; 引言 thinkphp* 大道至简一、分库分表分表php 分库分表hash算法0、分表的方法&#xff08;thinkphp&#xff09;1、ThinkPHP6 业务分表之一&#xff1a;UID 发号器2、ThinkPHP6 业务分表之二&#xff1a;用…

希尔排序(C语言实现)

目录 1.希尔排序( 缩小增量排序 ) 2.动图 ​编辑 3.代码实现 预排序实现 子序列排列实现 单趟排序实现 对整组数进行子排序 希尔排序代码 代码测试 时间复杂度分析 希尔排序的特性总结&#xff1a; 1.希尔排序( 缩小增量排序 ) 基本思想&#xff1a; 1.先选定一个…

QTCreator 调试:unknown debugger type “No engine“

QTCreator 调试&#xff1a;unknown debugger type "No engine" - kaizenly - 博客园 (cnblogs.com) 一开始Debuggers---Auto-detected这里第一row第一个项是标红的&#xff0c;然后没改东西&#xff0c;点完应用Apply以后&#xff0c;就可以调试了...&#xff08;不…

在python爬虫中xpath方式提取lxml.etree._ElementUnicodeResult转化为字符串str类型

简单提取网页中的数据时发现的 当通过xpath方式提取出需要的数据的text文本后想要转为字符串&#xff0c;但出现lxml.etree._ElementUnicodeResult的数据类型不能序列化&#xff0c;在网上查找到很多说是编码问题Unicode编码然后解码什么的&#xff1b;有些是(导入的xml库而不…

深度学习之概率论预备知识点(3)

在深度学习中&#xff0c;概率论和数理统计是理解许多算法背后的理论基础。这些知识在处理不确定性、估计模型参数、理解数据分布等方面非常关键 1、概率 一种用来描述随机事件发生的可能性的数字度量&#xff0c;表示某一事件发生的可能性。 概率并不客观存在&#xff0c;是…

Android Choreographer 监控应用 FPS

Choreographer 是 Android 提供的一个强大的工具类&#xff0c;用于协调动画、绘制和视图更新的时间。它的主要作用是协调应用的绘制过程&#xff0c;以确保流畅的用户体验。Choreographer 也可以帮助我们获取帧时间信息&#xff0c;从而为性能监测和优化提供重要的数据支持。 …

IDEA中Quarkus框架(3.13版本)开发、调试、部署、打包等

code-with-quarkus code-with-quarkus 是使用官网生成的demo项目 这个项目使用Quarkus&#xff08;使用3.13.0版本&#xff0c;该版本支持JDK21&#xff09;&#xff0c;超音速亚原子Java框架。官网地址: https://quarkus.io/. 环境要求 OS: Windows 10.0 jdk 11 maven 3.9…

淘宝扭蛋机小程序,扭蛋机文化下的新体验

在数字化时代中&#xff0c;扭蛋机逐渐从传统的线下机器转移到了线上互联网中&#xff0c;市场得到了创新发展。扭蛋机小程序具有便捷、多样化、个性化的特点&#xff0c;迎合了当下消费者的线上消费习惯&#xff0c;又能够让扭蛋机玩家体验到新鲜有趣的扭蛋。 扭蛋机是一种热…

python简单的小项目-关于央行储蓄占比情况的数据可视化

该数据来源于锐思数据库&#xff0c;如果数据有偏差&#xff0c;可能是本人搜索的问题&#xff0c;希望大家谅解。 数据大纲&#xff1a; 其中我们制作折现统计图需要用到的是截止日期&#xff0c;表达数据最后获取的日期&#xff0c;而更新时间则是数据时效性的表示&#xff…