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

Rust运算符

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

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

https://blog.csdn.net/brucexia/category_12779443.html

前面已经学习了变量和常量,本节开始对它们进行操作,这就要用到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:4a = b;                      // a:4,b:4b = 7;                      // a:4,b:7println!("{},{}",a,b);}

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

   运行结果如下:

4,7

4.1.2  数学运算符

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为2b = 4+a;                    //加法运算得b为6c =(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:2b = 4+a;            // b:6c =(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的关系运算符。

示例代码如下:

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);}

运行结果:true,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所示。

例如:

  • ( (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所示。

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

fn main() {let a:i32 = 2;     // 二进制表示为 0 0 0 0 0 0 1 0let b:i32 = 3;     // 二进制表示为 0 0 0 0 0 0 1 1let 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排列。

以下是简单的示例:

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 = 31 - 2 = -1true AND false is falsetrue OR false is trueNOT true is false0011 AND 0101 is 00010011 OR 0101 is 01110011 XOR 0101 is 01101 << 5 is 320x80 >> 2 is 0x20

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

a = 5 + 7 % 2;

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

a = 5 + (7 % 2);

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

a = (5 + 7) % 2;

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Nacos1.X中对NacosNamingService的实现
  • Google大数据架构技术栈
  • HOT 100(七)栈、堆、贪心算法
  • 定时任务和延时任务
  • 前端页面中使用 ppt 功能,并且可以随意插入关键帧
  • uniapp的苹果全屏播放再退出会导致页面字体变大解决方法
  • C语言代码练习(第二十三天)
  • 【Hot100】LeetCode—169. 多数元素
  • Python 课程6-Pandas 和 Matplotlib库
  • 102.WEB渗透测试-信息收集-FOFA语法(2)
  • 【Linux】数据链路层
  • Spring3-IoC1-IoC容器、基于xml管理bean
  • Android 源码多个Launcher设置默认Launcher
  • 『功能项目』C#拓展 - 优化冗余脚本【36】
  • 目标检测从入门到精通——数据增强方法总结
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 03Go 类型总结
  • AWS实战 - 利用IAM对S3做访问控制
  • Brief introduction of how to 'Call, Apply and Bind'
  • canvas 绘制双线技巧
  • Druid 在有赞的实践
  • IDEA常用插件整理
  • JavaScript 一些 DOM 的知识点
  • js正则,这点儿就够用了
  • php ci框架整合银盛支付
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Redis 中的布隆过滤器
  • STAR法则
  • tab.js分享及浏览器兼容性问题汇总
  • underscore源码剖析之整体架构
  • Zepto.js源码学习之二
  • 从重复到重用
  • 给第三方使用接口的 URL 签名实现
  • 关于List、List?、ListObject的区别
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 基于webpack 的 vue 多页架构
  • 技术发展面试
  • 前端技术周刊 2018-12-10:前端自动化测试
  • 主流的CSS水平和垂直居中技术大全
  • # include “ “ 和 # include < >两者的区别
  • ###STL(标准模板库)
  • #微信小程序:微信小程序常见的配置传旨
  • (02)vite环境变量配置
  • (16)Reactor的测试——响应式Spring的道法术器
  • (26)4.7 字符函数和字符串函数
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (黑马C++)L06 重载与继承
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (正则)提取页面里的img标签
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)