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

Rust教程:How to Rust-基本类型

专栏简介

本专栏是优质Rust技术专栏,推荐精通一门技术栈的蟹友,不建议完全无计算机基础的同学

感谢Rust圣经开源社区的同学,为后来者提供了非常优秀的Rust学习资源

本文使用:

  • 操作系统macOS Sonoma 14 / Apple M1
  • 编译器:Rustc & Cargo

感谢一路相伴的朋友们,感谢你们的支持 ^ _ ^

Rust教程:How to Rust-基本类型


目录

专栏简介

更新记录

前言

整型

整型溢出

浮点型

NaN

 使用As进行类型转换

结语

本文参考文献


更新记录

2024.3.24 发布文章


前言

Rust中的整型怎么写?整型溢出会怎么样?浮点型呢?NaN是什么?如何进行类型转换?


整型

Rust的类型系统与其他编程语言有许多相似之处,但Rust对类型的处理有其独特之处。在Rust中,整数类型的符号大小直接体现在类型名称中,这有助于清晰地表达每个类型的取值范围。

Rust的整数类型如下:

Rust整数类型
长度有符号类型无符号类型
8位i8u8
16位i16

u16

32位i32u32
64位i64

u64

128位i128u128
视架构isizeusize

类型定义的形式统一为:有无符号 + 大小(位数)。无符号数表示数字只能取正数和0,而有符号则表示数字可以取正数、负数以及0。就像我们在纸上写数字一样,当需要强调符号时,数字前面可以带上正号或负号;然而,当很明显确定数字为正数时,就不需要加上正号了。有符号数字在Rust中是以补码形式存储的。

在Rust编程语言中,isizeusize是两个与平台相关的整数类型。它们的大小取决于目标机器的指针大小。isize是一个有符号整数类型,其大小与机器的字大小相同。在32位系统上,isize通常是32位;在64位系统上,isize通常是64位。usize则是相应的无符号版本。

整型溢出

关于整型溢出,Rust有一些特别的规则。当在debug模式编译时,Rust会检查整型溢出,并在发现溢出时使程序panic(即崩溃)。然而,在release模式下编译时,Rust不检测溢出,而是按照补码循环溢出的规则处理。这意味着大于该类型最大值的数值会被转换成该类型能够支持的对应的最小值。例如,在u8类型中,256会变成0,257会变成1,以此类推。

为了显式处理可能的溢出,Rust标准库为原始数字类型提供了一系列方法:

  • 使用wrapping_*方法在所有模式下都按照补码循环溢出规则处理,例如wrapping_add
  • 如果使用checked_*方法时发生溢出,则返回None值。
  • 使用overflowing_*方法返回该值和一个指示是否存在溢出的布尔值。
  • 使用saturating_*方法,可以限定计算后的结果不超过目标类型的最大值或不低于最小值。

例如:

let result1 = (250_u8).wrapping_add(10); // 结果是 4
let result2 = (120_i8).wrapping_add(10); // 结果是 -126
let result3 = (300_u16).wrapping_mul(800); // 结果是 43392
let result4 = (-100_i8).wrapping_sub(100); // 结果是 56

在这些例子中,wrapping_*方法用于在溢出时按照补码循环溢出的规则进行处理,而不是使程序崩溃。然而,需要注意的是,依赖这种默认行为的代码通常被认为是错误的,因为它可能导致程序中的逻辑错误或数据损坏。在编写涉及整数运算的代码时,应该仔细考虑如何处理可能的溢出情况,并使用适当的方法来检查或处理它们


浮点型

浮点类型数字是带有小数点的数值,在Rust中,主要有两种浮点类型:f32f64,分别对应32位和64位大小的浮点数。默认情况下,Rust使用f64作为浮点类型,因为在现代CPU上,尽管f32f64的速度相差无几,但f64提供了更高的精度。

let variable_float = 2.0;
let variable_f32: f32 = 3.0;

变量variable_float的类型是默认的f64,而变量variable_f32的类型则是显式声明的f32。当然,你也可以显式声明f64类型的变量,例如:

let variable_f64: f64 = 4.0;

使用浮点数时,如果不谨慎,可能会带来一些潜在的危险。这主要有两个原因:

首先,浮点数通常是用来近似表达你想要的数值。请注意,这里的“近似表达”是因为浮点数类型是基于二进制实现的,而我们通常使用的数字则是基于十进制的。例如,数值0.1在二进制中无法精确表示,这导致了一定的歧义。尽管浮点数能够代表真实的数值,但由于其底层格式的限制,它通常受限于定长的浮点数精度。如果你需要表达完全精确的真实数字,则需要使用具有无限精度的数学库。

其次,浮点数在某些特性上是反直觉的。虽然可以使用>>=等运算符对浮点数进行比较,但在某些场景下,这种直觉上的比较特性可能会导致错误。f32f64上的比较运算实现了std::cmp::PartialEq特性,但并没有实现std::cmp::Eq特性,而后者在其他数值类型上都有定义。

来看个例子

fn main()
{assert_eq!(0.1 + 0.2, 0.3); // 这行代码会触发 panic,因为二进制精度问题导致 0.1 + 0.2 不严格等于 0.3
}

上述代码中,第三行是一个断言,断言0.1 + 0.2的结果就是0.3。然而,由于二进制精度的问题,0.1 + 0.2并不严格等于0.3,它们之间可能存在小数点后某位的误差,这与大多数编程语言中的浮点数行为是一致的。

NaN

对于数学上未定义的结果,如负数开平方根,Rust的浮点数类型会使用NaN(Not a Number)来处理这些情况。任何与NaN进行交互的操作都会返回NaN,并且NaN不能用于比较(如断言),这会导致程序崩溃。

例如,以下代码会产生NaN:

fn main()
{let variable = (-1.1_f64).sqrt();
}

为了避免程序因NaN而崩溃,我们可以使用一些方法来检查数值是否为NaN,例如使用.is_nan()方法:

fn main()
{let variable = (-1.1_f64).sqrt();if variable.is_nan(){println!("NaN")}
}

使用.is_nan()可以帮助我们安全地处理可能产生NaN的浮点数运算。 

 使用As进行类型转换

在Rust中,as关键字用于在原始类型(如i64f64u64char等)之间进行类型转换。然而,需要注意的是,as关键字并不适用于复合类型,比如String或其他用户定义的类型。对于复合类型的转换,通常需要使用其他方法或函数。

例如,如果你有一个i32类型的变量,并希望将其转换为f64类型的浮点数,你可以使用as关键字来实现这一转换:

let num_i32: i32 = 42;  
let num_f64: f64 = num_i32 as f64;

但是,as关键字的使用是有限制的,它只能在那些具有明确定义转换规则的类型之间起作用。如果尝试在不兼容的类型之间进行转换,Rust编译器会报错。例如,下面的代码尝试将一个String转换为i32,这是不允许的,因为Stringi32之间没有直接的转换关系:

let str_num = "123".to_string();  
let num_i32: i32 = str_num as i32; // 这行会报错,因为 String 不能直接转换为 i32

在上面的代码中,尝试使用as来转换str_num变量会导致编译错误,因为String类型不能直接用as关键字转换为i32类型。如果需要将字符串转换为整数,你需要使用其他方法,比如parse方法:

let str_num = "123";  
let num_i32: i32 = str_num.parse().unwrap(); // 使用 parse 方法来将字符串转换为整数

在上面的代码中,我们使用了parse()方法,该方法尝试将字符串解析为相应的数值类型,并返回一个Result枚举,表示解析操作是否成功。使用unwrap()方法可以获取解析结果,但如果解析失败(比如字符串不是有效的数字表示),则会触发panic。在实际应用中,通常需要对parse()的返回值进行更健壮的错误处理。

因此,在使用as进行类型转换时,需要确保转换的类型之间具有明确定义的转换关系,并且不适用于复合类型或没有直接转换关系的类型。对于更复杂的类型转换需求,需要利用Rust提供的相应函数或方法。


结语

如果本文有任何问题欢迎在评论去指出,如果喜欢这篇文章,希望能点赞评论关注

如果你们身边有像你提起过这个领域的,或者希望可以和ta一起进步的,把这篇文章分享给ta吧

本文共3646字


本文参考文献

Rust圣经

文心一言 

菜鸟求助,使用 isize 或 usize 作为索引类型更加灵活 - Rust语言中文社区

在 Rust 中处理整数溢出

https://www.cnblogs.com/ywxt/p/11801778.html

相关文章:

  • 探索数据库mysql--------------mysql主从复制和读写分离
  • 电脑关机速度很慢怎么解决?
  • L3-016 二叉搜索树的结构
  • LeetCode //C - 436. Find Right Interval
  • MySQL进阶-----索引的语法与SQL性能分析
  • 【Python百日进阶-Web开发-Peewee】Day290 - Peewee 的扩展(十)架构迁移(下)/ 映射
  • Unity 学习日记 12.小球撞击冰块游戏
  • RabbitMQ介绍
  • 【WPF应用16】WPF如何让Canvas上的元素响应鼠标点击事件?
  • 企业产品网络安全建设日志0328
  • 单源最短路径
  • Qlib-Server:量化库数据服务器
  • Apache HBase(二)
  • 康耐视visionpro-CogBlobTool工具详细说明
  • 指标监控和归因分析——数据异常波动
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • Android Volley源码解析
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • flutter的key在widget list的作用以及必要性
  • Java知识点总结(JavaIO-打印流)
  • Netty 4.1 源代码学习:线程模型
  • oschina
  • python大佬养成计划----difflib模块
  • Python进阶细节
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 笨办法学C 练习34:动态数组
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 理清楚Vue的结构
  • 前端面试之CSS3新特性
  • 使用Gradle第一次构建Java程序
  • 微服务入门【系列视频课程】
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​secrets --- 生成管理密码的安全随机数​
  • #laravel 通过手动安装依赖PHPExcel#
  • #Spring-boot高级
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (java)关于Thread的挂起和恢复
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (排序详解之 堆排序)
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)SpringBoot3---尚硅谷总结
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • **CI中自动类加载的用法总结
  • ./configure,make,make install的作用
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET MVC第五章、模型绑定获取表单数据
  • .Net Web项目创建比较不错的参考文章
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • // an array of int
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法