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;

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

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

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

相关文章

第三方软件测评机构分享:软件性能测试的测试方法和内容

软件性能测试是对软件系统在特定负载和条件下的性能进行评估的过程。它旨在确定软件的响应时间、稳定性、资源消耗及其可扩展性&#xff0c;以确保其在实际环境中能够满足用户的需求。通过性能测试&#xff0c;开发团队能够发现潜在的瓶颈问题&#xff0c;优化应用程序架构&…

前端:JavaScript 实现类

文章目录 1. Es6-类-class2. Es6-class 实现继承3. Es6-class 静态属性和私有属性4. Es5-寄生组合式继承 1. Es6-类-class 类是创建对象的模板&#xff0c;用代码封装数据以处理该数据&#xff0c;js中的类建立在原型上。 如何定义类&#xff0c;首先需要关键字 class&#x…

聊天组件 Vue3-beautiful-chat

前言 最近很多公司都在搞大模型&#xff0c;类似于 chatgpt 的功能&#xff1b;而 chatgpt 的界面其实就是个对话框。今天就介绍一个不错的对话框组件 Vue3-beautiful-chat 项目框架 vite vue3 TS Vue3-beautiful-chat 使用流程 1、引用三方件 npm install Vue3-beaut…

【JAVA基础】实现Tomcat基本功能

文章目录 TCP/IP协议Socket编程ServletTomcat 在搜索了两三天之后&#xff0c;也是大概弄懂了Tomcat是个什么东西&#xff0c;我们在说Tomcat之前&#xff0c;先来了解一下下面这三个东西&#xff1a; TCP/IP协议 TCP/IP 是互联网通信的基础协议。TCP&#xff08;传输控制协议…

SpringBoot框架下的房产销售系统开发

第一章 绪 论 1.1背景及意义 房产销售也都将通过计算机进行整体智能化操作&#xff0c;对于房产销售系统所牵扯的管理及数据保存都是非常多的&#xff0c;例如管理员&#xff1b;首页、个人中心、用户管理、销售经理管理、房源信息管理、房源类型管理、房子户型管理、交易订单管…

《Python青少年趣味编程108例》书籍介绍

文章目录 前言为什么选择Python&#xff1f;书籍介绍文章目录配套资源 前言 在这个数字化飞速发展的时代&#xff0c;编程已经成为了一项不可或缺的技能。对于青少年而言&#xff0c;学习编程不仅能够培养逻辑思维、解决问题的能力&#xff0c;还能激发无限创意&#xff0c;让…

【吊打面试官系列-Redis面试题】如果有大量的 key 需要设置同一时间过期,一般需要注意什么?

大家好&#xff0c;我是锋哥。今天分享关于【如果有大量的 key 需要设置同一时间过期&#xff0c;一般需要注意什么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 如果有大量的 key 需要设置同一时间过期&#xff0c;一般需要注意什么&#xff1f; 如果大量的…

Windows terminal使用说明

1 terminal基本介绍 1 下载 从微软商店上下载的方式网速比较慢&#xff0c;一种直接的方式是直接用命令行运行命令 winget install --idMicrosoft.WindowsTerminal -e# Window Terminal 安装以及使用(2021最新) 2 ssh配置 # 使用Windows Terminal进行SSH登录 1 通过label…

安泰功率放大器的使用方法及注意事项有哪些

功率放大器是一种用来增加输入信号功率的电子设备。它在各种电子设备和通信系统中被广泛应用&#xff0c;如音响设备、收发器、无线通信设备等。使用功率放大器时&#xff0c;有一些重要的注意事项需要注意&#xff0c;以确保其正常运行并保护设备。 首先&#xff0c;正确的功率…

【数据结构与算法 | 灵神题单 | 分治(链表)篇】力扣148

1. 力扣148&#xff1a;排序链表 1.1 题目&#xff1a; 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4…

Unity程序基础框架

概述 单例模式基类 没有继承 MonoBehaviour 继承了 MonoBehaviour 的两种单例模式的写法 缓存池模块 &#xff08;确实挺有用&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine;/// <summary> /// 缓存池模块 /// 知识点 //…

C++STL~~stackqueue

文章目录 容器适配器一、stack&queue的概念二、stack&queue的使用三、stack&queue的练习四、总结 容器适配器 什么是适配器 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结)&#xff0c;该种模式是将一个类…

Leetcode 移动零

要求将数组中的所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。下面是该题的 C 解决方案&#xff1a; class Solution { public:void moveZeroes(vector<int>& nums) {int nonZeroPos 0; // 记录非零元素应该放置的位置// 遍历数组&#xff0c;…

【北京迅为】《STM32MP157开发板使用手册》- 第三十章Cortex-M4通用定时器实验

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

相图的科学应用,陶瓷材料创新

陶瓷材料因其优异的物理和化学性能&#xff0c;在航空航天、电子、生物医学等多个领域展现出广阔的应用前景。陶瓷材料的性能很大程度上取决于其微观结构&#xff0c;包括晶粒大小、相组成和分布。相图作为描述陶瓷材料在不同条件下的相变行为和相平衡关系的图表反映了陶瓷材料…

Element-ui el-table 全局表格排序

实现效果如下&#xff1a; 一、当页数据排序 如果只想要当前页面排序&#xff0c;只会涉及到前端&#xff0c;只需在<el-table-column>标签上添加 :sortable"true"即可 二、自定义排序 如果想要全局排序&#xff0c;需要自定义排序函数&#xff0c;请求后台排…

Springboot项目打war包运行及错误解决

一,打war包 1. 修改pom.xml 为了不影响原pom.xml, 我复制了一个文件叫pom_war.xml , 需要打war包就采用pom_war.xml进行打war包, 你也可以直接修改pom.xml ① 打包方式改为war 没有就增加此配置 <packaging>war</packaging> ② 排除内嵌tomcat依赖 <de…

怎样在备忘录中添加提醒?怎么设置备忘录提醒

备忘录作为我们日常生活中常用的软件&#xff0c;其记录事项的便捷性已经得到了广泛认可。无论是工作计划、购物清单还是个人日记&#xff0c;备忘录都能帮助我们将这些信息快速记录下来。然而&#xff0c;如果备忘录能够进一步提供提醒功能&#xff0c;那么它将变得更加实用&a…

122.rk3399 uboot(2017.09) 源码分析2-initf_dm(2024-09-09)

这里接着上一篇来吧&#xff1a; https://blog.csdn.net/zhaozhi0810/article/details/141927053 本文主要是dm_init_and_scan函数的分析&#xff0c;这个内容比较复杂&#xff0c;我也是第一次阅读&#xff0c;错误之处在所难免&#xff0c;请多指教。 uboot的dm框架需要了解…

MyBatis 面试题11-27

11、Mybatis 是如何将 sql 执行结果封装为目标对象并返回的? 都有哪些映射形式&#xff1f; Mybatis 在执行 SQL 查询后&#xff0c;会将结果集封装为目标对象并返回。这主要依赖于 Mybatis 的映射机制&#xff0c;它提供了两种主要的映射形式&#xff1a; 第一种&#xff1…