在rust里数据类型可以分为标量(scalar)和复合(compound)类型,标量类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。rust是静态强类型语言,它在编译时就需要知道所有变量的类型,并且不同类型的数据之间是不允许进行运算的。
rust根据整数占据的二进制位数,提供了以下多种整数类型。可以根据业务的实际场景进行选择。当你没有指定整数的类型时,rust 整型默认使用 i32类型。无符号数表示数字只能取非负数,而有符号则表示数字既可以取非负数,也可以取负数。
类型长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
需要注意的是arch,它表示长度取决于CPU的架构。isize 和 usize 类型取决于程序运行的计算机 CPU 类型: 若 CPU 是 32 位的,则这两个类型是 32 位的,同理,若 CPU 是 64 位,那么它们则是 64 位。isize 和 usize 的主要应用场景是用作集合数据类型的索引。
一个有符号的变量可以储存包含从 -2^(n-1) 到 2^(n-1)-1 之间的数值,n是类型的长度;而无符号数存储的范围为 0 到 2^(n-1)之间。
当在 debug 模式编译时,Rust 会检查整型溢出,若存在这些问题,则使程序在编译时 panic(崩溃,Rust 使用这个术语来表明程序因错误而退出)。在当使用 --release 参数进行 release 模式构建时,Rust 不检测溢出。 当整型溢出时,Rust 会按照补码循环溢出(two’s complement wrapping)的规则处理。要显式处理可能的溢出,可以使用标准库针对原始数字类型提供的这些方法:
fn main() {
let a: i8 = 127;
let b: i8 = a.wrapping_add(1); // 所有模式下都按照补码循环溢出规则
println!("{b}");
let b:Option<i8> = a.checked_add(0);
if b.is_none(){ // 发生溢出时,返回None值。
println!("溢出");
}else{
println!("{:?}", b.expect(""));
}
let tup = a.overflowing_add(1); //返回一个数值以及指示是否溢出的bool值。
println!("{}, {}", tup.0, tup.1); // tup是一个元组,取其中的第0个和第1个元素的值。
let b = a.saturating_add(1); //使值达到最大值(或者最小值)
println!("{b}");
}
浮点类型数字 是带有小数点的数字,在 Rust 中浮点类型数字也有两种基本类型: f32 和 f64,分别为 32 位和 64 位大小。默认浮点类型是 f64。浮点数采用 IEEE-754 标准表示。f32 是单精度浮点数,f64 是双精度浮点数。
对于数学上未定义的结果,Rust使用NaN来处理这些结果。所有跟 NaN 交互的操作,都会返回一个 NaN,而且两个 NaN 之间是不能用来比较的。一个防御性编程的例子如下所示:
fn main() {
let x = (-42.0_f32).sqrt();
if x.is_nan() {
println!("未定义的数学行为")
}
}
Rust 支持所有数字类型的基本数学运算:加法、减法、乘法、除法和取模运算。如下所示。
fn main() {
// 加法
let sum = 5 + 10;
println!("{}", sum);
// 减法
let difference = 95.5 - 4.3;
println!("{}", difference);
// 乘法
let product = 4 * 30;
println!("{}", product);
// 除法
let quotient = 56.7 / 32.2;
println!("{}", quotient);
// 求余
let remainder = 43 % 5;
println!("{}", remainder);
}
再次强调,Rust是一门强类型语言,不同类型之间不允许进行运算。例如可以在上述代码中混合计算整型和浮点型,将会导致错误。
fn main() {
let sum: f64 = 12i32 + 3.3_f64; // 错误,rust无法将i32和f64进行相加操作。
println!("{sum}")
}
数字类型的数字字面值允许使用类型后缀,例如上面的12i32来指定12这个数字是i32类型,同时也允许使用 _ 做为分隔符以方便人类读,例如:3.3_f64。同时_也可以和python中类似,用来对大数进行多位分割书写。例如:
let x: i64 = 100_0000_0000;
为了让i32和f64直接可以进行运算,Rust要求必须对其中一个类型进行显示类型转换,让它们变成同一个类型。在Rust中可以使用as运算符进行数据类型转换。例如:
fn main() {
// let sum: f64 = 12i32+ 3.3_f64; // 错误
let mut sum: f64 = 12i32 as f64+ 3.3_f64; // 进行显示类型转换
println!("{sum}");
sum = (12_i32 + 3.3_f64 as i32).into(); // 先将3.3从f64转为i32,那么3.3就会变成3,然后在将12+3的结果转为f64
println!("{sum}");
sum = (12_i32 + 3.3_f64 as i32) as f64; // 等价于into()
println!("{sum}");
}
另外一个需要注意的例子如下所示:
fn main() {
println!("{}", 1u8 + 21);
}
这个例子是可以正常运行的,它背后的原理是rust编译器会推断21这个数字的类型为u8,这样就相当于是1u8 + 21u8,所以可以正常运行。
布尔类型表示真假。在Rust中,使用关键字bool表示,其有两个值true和false。布尔值占用内存的大小为 1 个字节。布尔类型的场景主要在于流程控制。
在Rust中,使用char表示字符类型,和C/C++语言中类似,不同的是Rust的char类型大小为4个字节,并且是一个Unicode字符。注意,前面我们在代码中使用双引号(“”)来声明的不是字符类型,而是字符串类型;字符类型使用单引号(‘’)声明。下面是一个例子。
fn main() {
let c1:char = '☺';
let c2:char = '秀';
let c3:char = 'a';
println!("{c1}");
println!("{c2}");
println!("{c3}");
}
下面是数据类型之间的共同点总结