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的整数类型如下:

长度 有符号类型 无符号类型
8位 i8 u8
16位 i16 u16
32位 i32 u32
64位 i64 u64
128位 i128 u128
视架构 isize usize
[Rust整数类型]

类型定义的形式统一为:有无符号 + 大小(位数)。无符号数表示数字只能取正数和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_*方法,可以限定计算后的结果不超过目标类型的最大值或不低于最小值。

例如:

rust 复制代码
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提供了更高的精度。

rust 复制代码
let variable_float = 2.0;
let variable_f32: f32 = 3.0;

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

rust 复制代码
let variable_f64: f64 = 4.0;

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

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

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

来看个例子

rust 复制代码
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:

rust 复制代码
fn main()
{
    let variable = (-1.1_f64).sqrt();
}

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

rust 复制代码
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关键字来实现这一转换:

rust 复制代码
let num_i32: i32 = 42;  
let num_f64: f64 = num_i32 as f64;

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

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

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

rust 复制代码
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

相关推荐
一丝晨光11 分钟前
gcc 1.c和g++ 1.c编译阶段有什么区别?如何知道g++编译默认会定义_GNU_SOURCE?
c语言·开发语言·c++·gnu·clang·gcc·g++
南城花随雪。22 分钟前
Spring框架之装饰者模式 (Decorator Pattern)
java·开发语言·装饰器模式
究极无敌暴龙战神X27 分钟前
前端学习之ES6+
开发语言·javascript·ecmascript
虞书欣的633 分钟前
Python小游戏24——小恐龙躲避游戏
开发语言·python·游戏·小程序·pygame
源码121538 分钟前
ASP.NET MVC宠物商城系统
后端·asp.net·宠物
FHYAAAX41 分钟前
【机器学习】任务十:从函数分析到机器学习应用与BP神经网络
开发语言·python
汉克老师1 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
爱吃生蚝的于勒2 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
Ai 编码助手2 小时前
Go语言 实现将中文转化为拼音
开发语言·后端·golang
hummhumm2 小时前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang