Rust 是一门强调安全、并发、高效的系统编程语言。无 GC 实现内存安全机制、无数据竞争的并发机制、无运行时开销的抽象机制,是 Rust 独特的优越特性。 它声称解决了传统 C 语言和 C++语言几十年来饱受责难的内存安全问题,同时还保持了很高的运行效率、很深的底层控制、很广的应用范围, 在系统编程领域具有强劲的竞争力和广阔的应用前景。
接下来,为了快速入门 Rust,我们一起梳理 Rust 开发的基本内容。
Rust 每个值都有其确切的数据类型,总的来说可以分为两类:基本类型和复合类型。 基本类型意味着它们往往是一个最小化原子类型,无法解构为其它类型(一般意义上来说),由以下组成:
- 数值类型: 有符号整数 (i8, i16, i32, i64, isize)、 无符号整数 (u8, u16, u32, u64, usize) 、浮点数 (f32, f64)、以及有理数、复数
- 布尔类型: true和false
- 字符类型: 表示单个 Unicode 字符,存储为 4 个字节
- 单元类型: 即 () ,其唯一的值也是 ()
本文先带大家了解一下 Rust 的基本类型。
1. 数值类型
1.1 整数类型
整数类型分为有符号整数和无符号整数。 例如:i32 表示有符号的 32 位整数。 例如:u32 表示无符号的 32 位整数。 i 是英文单词 integer 的首字母,与之相反的是 u,代表无符号 unsigned 类型。
长度 | 有符合类型 | 无符合类型 |
---|---|---|
8 位 | i8 | u8 |
16 位 | i16 | u16 |
32 位 | i32 | u32 |
64 位 | i64 | u64 |
128位 | i128 | u128 |
待定 | isize | usize |
有符号则表示数字可以取正数、负数还有0。无符号数表示数字只能取正数和0。
每个有符号类型规定的数字范围是 -(2^(n 1)) ~ 2^(n - 1)-1其中 n 是该定义形式的位长度。因此 i8 可存储数字范围是 -(2^7)~~ 2^7-1,即 -128 ~ 127。
rust
let _a: i8 = 127;
无符号类型可以存储的数字范围是 0 ~ 2^n- 1,所以 u8 能够存储的数字为 0 ~ 2^8- 1,即 0 ~ 255。
rust
let _a: u8 = 255;
既然每一个类型都决定了数字的范围,那如果我们定义的数字超过了这个范围会怎么样了? 例如:
rust
let _i: u8 = 256;
let _x: i8 = 128;
当在 debug 模式编译时,Rust 会检查整型溢出,若存在这些问题,则使程序在编译时崩溃。 当在 -- release 模式构建时,Rust 不检测溢出。当检测到整型溢出时,Rust 会按照补码循环溢出的规则处理。比如在 u8 的情况下,256 变成 0,257 变成 1。
此外,isize 和 usize 类型取决于程序运行的计算机 CPU 类型: 若 CPU 是 32 位的,则这两个类型是 32 位的,同理,若 CPU 是 64 位,那么它们则是 64 位。
我们知道 Rust 是一门静态类型语言,意思它会进行类型推导, Rust 整型默认使用 i32,例如:
rust
let _i = 1;
那 i 就是 i32 类型,这是 Rust 的默认类型推导。
1.2 浮点类型
在 Rust 中浮点类型数字也有两种基本类型: f32 和 f64,分别为 32 位和 64 位大小。默认浮点类型是 f64。
rust
let x = 2.0; // f64
let y: f32 = 3.0; // f32
浮点数根据 IEEE-754 标准实现。f32 类型是单精度浮点型,f64 是双精度浮点型。
在 Rust 同样存在 0.1 + 0.2 === 0.3 的问题。
rust
fn main() {
// 断言0.1 + 0.2与0.3相等
assert!(0.1 + 0.2 == 0.3);
}
因为二进制精度问题,导致了 0.1 + 0.2 并不严格等于 0.3,它们可能在小数点 N 位后存在误差。 可以考虑用这种方式 (0.1_f64 + 0.2 - 0.3).abs() < 0.00001 ,来进行比较,这里的具体小于多少,取决于你对精度的需求。 对于 Rust 的浮点类型,问题还远远不止上面一个,比如还有:
rust
fn main() {
let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);
println!(" 0.1 + 0.2: {:?}", (abc.0 + abc.1));
println!(" 0.3: {:?}", (abc.2));
let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);
println!(" 0.1 + 0.2: {:?}", (xyz.0 + xyz.1));
println!(" 0.3: {:?}", (xyz.2));
}
在 f64 类型 01 + 0.2 = 0.30000000000000004,因为 f64 精度高很多,因此在小数点非常后面发生了一点微小的变化。 但是 32 下的 0.1 + 0.2 == 0.3 通过测试。 在 Rust 中也存在 NaN,对于未定义的结果那么 Rust 就会使用 NaN 来处理。 在 Rust 可以通过 is_nan 方法来判断一个数字是否是 NaN:
1.3 有理数和复数
对于前端同学来说,有理数和复数这两个类型可能没有听过。但是我想大家一定用过。
有理数是一个整数 a 和一个非零整数 b 的比,例如 3/8,通则为 a/b ,又称作分数。0也是有理数。有理数是整数和分数的集合,整数也可看做是分母为一的分数。有理数的小数部分是有限或为无限循环的数。不是有理数的实数称为无理数,即无理数的小数部分是无限不循环的数。而有理数和无理数统称为实数。
那么复数是指能写成如下形式的数 a+bi,这里 a 和 b 是实数,i 是虚数单位(即-1开根)。在复数 a + bi 中,a 称为复数的实部,b 称为复数的虚部,i 称为虚数单位。当虚部等于零时,这个复数就是实数;当虚部不等于零时,这个复数称为虚数。
在现阶段的 Rust 标准库中,还没有正式的包含的有理数和复数,但是在 Rust 社区中已经存在 Rust 数值库 num。这个库是 Rust 的数字类型和特征的集合,包括 bigint、complex、rational、范围迭代器、泛型整数等等!这里就不花过多的篇章来讲了。
2.字符类型
Rust 的字符不仅仅是 ASCII,所有的 Unicode 值都可以作为 Rust 字符,包括中文、日文、韩文、emoji 表情符号等等,都是合法的字符类型。Unicode 值的范围从 U+0000 ~ U+D7FF 和 U+E000 ~ U+10FFFF。不过"字符"并不是 Unicode 中的一个概念,所以人在直觉上对"字符"的理解和 Rust 的字符概念并不一致。
在 Rust 中字符只能用 '' 来表示, "" 是留给字符串的。 并且还需要注意区分的是字符的 char,而不是 &str。
rust
let _a: char = 'b';
let _b: &str = "abc";
3.布尔类型
Rust 中的布尔类型和 JS 中一样有两个可能的值:true 和 false。
rust
let _t: bool = true;
let _f: bool = false;
4.单元类型
单元类型就是 (),也叫做 unit。 Rust 函数参数的类型和返回值的类型都必须显式定义,如果没有返回值可以省略,返回 unit。函数内部如果提前返回,需要用 return 关键字,否则最后一个表达式就是其返回值。如果最后一个表达式后添加了; 分号,隐含其返回值为 unit。
main 函数就返回这个单元类型 (),println!() 的返回值也是单元类型 ()。