文章目录
- 数据类型
- 1.标量类型
- 1. 整数类型
- 2.浮点数类型
- f32 和 f64
- 示例代码
- 注意事项
- 3.布尔类型
- 4.字符类型
- 2.复合类型
- 整数类型技术细节
- 1. 检查溢出(Checking Overflow)
- 2. 溢出时 panic(Panic on Overflow)
- 3. 使用 Wrapping 模式(Wrapping Behavior)
数据类型
在Rust中,每个值都有一个明确的数据类型,这告诉Rust如何处理这个值。数据类型分为两类子集:标量(scalar)和复合(compound)。
需要记住的是,Rust是一种静态类型语言,这意味着在编译时必须知道所有变量的类型。通常情况下,根据值及其使用方式,编译器可以推断出我们想要的类型。
1.标量类型
在Rust中,标量类型代表单个的简单数据。主要的标量类型包括:
-
整数类型(Integer Types):表示整数值,可以是有符号或无符号的。例如,
i32
表示有符号的 32 位整数,u64
表示无符号的 64 位整数。 -
浮点数类型(Floating-Point Types):表示带有小数点的数值。例如,
f64
表示双精度浮点数。 -
布尔类型(Boolean Type):表示逻辑值,只能是
true
或false
。 -
字符类型(Character Type):表示单个 Unicode 字符,用单引号括起来,例如
'a'
。
1. 整数类型
下面是 Rust 中整数类型的表格形式:
长度 | 有符号类型 | 无符号类型 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
在Rust中,有符号整数类型可以表示正数、负数和零,而无符号整数类型只能表示非负数(即零和正数),不能表示负数。
具体来说:
-
有符号整数类型(Signed Integer Types):使用一位来表示符号(正或负),其余位表示数值。例如,对于
i8
类型,8 个位中的第一位表示符号,剩下的 7 位表示数值范围。 -
无符号整数类型(Unsigned Integer Types):所有位都用来表示数值,因此只能表示非负数。例如,对于
u8
类型,所有 8 个位都用来表示数值范围。
使用有符号类型或无符号类型取决于你的数据表示需求。通常情况下,如果你知道值永远不会是负数,可以选择无符号类型,这样可以利用更大的范围来表示正数。但如果负数也是可能的,那么需要使用有符号类型。
fn main() {// 有符号整数示例let x: i8 = -5; // 8-bit signed integerlet y: i16 = -300; // 16-bit signed integerlet z: i32 = -100000; // 32-bit signed integer// 无符号整数示例let a: u8 = 42; // 8-bit unsigned integerlet b: u16 = 500; // 16-bit unsigned integerlet c: u32 = 100000; // 32-bit unsigned integerprintln!("有符号整数示例:");println!("x: {}", x);println!("y: {}", y);println!("z: {}", z);println!("无符号整数示例:");println!("a: {}", a);println!("b: {}", b);println!("c: {}", c);}
在 Rust 中,标准库提供了一系列的整数类型,包括有符号和无符号的整数类型,以及不同位数的整数类型,用来满足不同的需求。
i8
、i16
、i32
、i64
、i128
是有符号整数类型,分别表示 8 位、16 位、32 位、64 位和 128 位的有符号整数。u8
、u16
、u32
、u64
、u128
是无符号整数类型,分别表示 8 位、16 位、32 位、64 位和 128 位的无符号整数。
这些整数类型都是 Rust 编程语言的一部分,用来在代码中表示不同范围和精度的整数值。
无符号整数类型只能表示非负数(即零和正数),不能表示负数。强行为负数会进行提示不可以这样这样编写并 且执行会报错
Rust 中各种整数类型的存储范围:
类型 | 存储大小 | 最小值(包括) | 最大值(包括) |
---|---|---|---|
i8 | 8 位 | -128 | 127 |
u8 | 8 位 | 0 | 255 |
i16 | 16 位 | -32,768 | 32,767 |
u16 | 16 位 | 0 | 65,535 |
i32 | 32 位 | -2,147,483,648 | 2,147,483,647 |
u32 | 32 位 | 0 | 4,294,967,295 |
i64 | 64 位 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
u64 | 64 位 | 0 | 18,446,744,073,709,551,615 |
i128 | 128 位 | -(2^127) | 2^127 - 1 |
u128 | 128 位 | 0 | 2^128 - 1 |
2.浮点数类型
Rust 有两个原生的 浮点数(floating-point numbers)类型,它们是带小数点的数字。Rust 的浮点数类型是 f32 和 f64,分别占 32 位和 64 位。默认类型是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。所有的浮点型都是有符号的。
f32 和 f64
f32
:单精度浮点数,占据 32 位内存空间,提供约 7 位有效数字的精度。f64
:双精度浮点数,占据 64 位内存空间,提供约 15-16 位有效数字的精度。
示例代码
fn main() {let x: f32 = 3.14;let y: f64 = 3.141592653589793;println!("x: {}", x);println!("y: {}", y);
}
32 位内存空间,提供约 7 位有效数字的精度。占据 64 位内存空间,提供约 15-16 位有效数字的精度。
示例代码中的f32和f64 是标准库提供的整数类型
注意事项
-
精度和范围:使用
f32
和f64
类型时,需要注意其精度和表示范围。f32
提供的精度相对较低,但范围更广,适用于需要节省内存空间或表示较大范围的浮点数。而f64
提供更高的精度,适用于对精度要求较高的场景。 -
浮点数运算:在进行浮点数运算时,需要注意浮点数的精度问题可能会导致精度损失和舍入误差。因此,在比较浮点数时,应该避免直接使用相等性比较,而应该考虑使用误差范围内的比较。
-
特殊值:浮点数类型支持特殊值,如正无穷大、负无穷大和 NaN(Not a Number)。这些特殊值可以通过相应的常量来表示,例如
std::f32::INFINITY
、std::f32::NEG_INFINITY
和std::f32::NAN
。
fn main() {let inf: f32 = std::f32::INFINITY;let neg_inf: f32 = std::f32::NEG_INFINITY;let nan: f32 = std::f32::NAN;println!("Positive Infinity: {}", inf);println!("Negative Infinity: {}", neg_inf);println!("NaN: {}", nan);
}
在 Rust 中,使用浮点数类型需要谨慎处理精度和范围,并且需要了解浮点数运算可能存在的误差和特殊值。
3.布尔类型
Rust 中的布尔类型使用 bool 表示,它只有两个可能的值:true 和 false。与其他大多数编程语言一样
fn main() {let is_raining = true;let is_sunny: bool = false;if is_raining {println!("Remember to bring an umbrella!");} else if is_sunny {println!("Don't forget your sunglasses!");} else {println!("Enjoy the weather!");}
}
4.字符类型
Rust 的 char 类型是语言中最原生的字母类型,Rust的 char 类型大小为 4 个字节,代表 Unicode标量值,这意味着它可以支持中文,日文和韩文字符等非英文字符甚至表情符号和零宽度空格在 Rust 中都是有效的 char 值。
fn main() {let heart_emoji = '❤';let zh_character = '中';let smiley = '😊';println!("Heart Emoji: {}", heart_emoji);println!("Chinese Character: {}", zh_character);println!("Smiley: {}", smiley);
}
在 Rust 中,要注意用单引号表示字符字面量,而双引号则用于字符串字面量。Char 类型大小为四个字节,代表 Unicode 标量值,因此支持各种语言字符、表情符号和零宽度空格。需要留意的是,Unicode 中不存在 “字符” 这一概念,因此人们的直觉可能与 Rust 的 char 不完全匹配。Unicode 标量值范围广泛,从 U+0000 到 U+D7FF 和 U+E000 到 U+10FFFF。
2.复合类型
在 Rust 中,复合类型是指能够将多个值组合在一起的类型。这些类型允许你在一个变量中存储多个值,并以某种方式对它们进行组织和访问。主要的复合类型包括元组(Tuple)和数组(Array)。
-
元组(Tuple):元组是一个固定大小的有序集合,可以包含不同类型的元素。元组使用圆括号
()
表示,元素之间用逗号,
分隔。元组的长度是固定的,一旦创建后不能改变。元组允许通过索引访问其中的元素。let my_tuple: (i32, f64, char) = (10, 3.14, 'A');
元组的长度是固定的长度是固定的因此 定义长度之后必须要把值填满,否则会报错哦
fn main() {let tup = (500, 6.4, 1);let (x, y, z) = tup;println!("The value of y is: {y}");
}
程序首先创建了一个元组并绑定到 tup 变量上。接着使用了 let 和一个模式将 tup 分成了三个不同的变量,x、y 和 z。这叫做 解构(destructuring),因为它将一个元组拆成了三个部分。最后,程序打印出了 y 的值,也就是 6.4。
在 Rust 中,你可以使用元组的索引值来访问元组中的特定元素。元组的索引从 0 开始,即第一个元素的索引是 0,第二个元素的索引是 1,以此类推。以下是一个简单的示例:
let my_tuple: (i32, f64, char) = (10, 3.14, 'A');// 访问第一个元素
let first_element = my_tuple.0;
println!("First element: {}", first_element); // 输出: First element: 10// 访问第二个元素
let second_element = my_tuple.1;
println!("Second element: {}", second_element); // 输出: Second element: 3.14// 访问第三个元素
let third_element = my_tuple.2;
println!("Third element: {}", third_element); // 输出: Third element: A
不带任何值的元组有个特殊的名称,叫做 单元
(unit) 元组
-
数组(Array):数组是一组相同类型的固定大小元素的集合。数组使用方括号
[]
表示,需要在声明时指定数组的长度。数组的长度也是固定的,一旦创建后不能改变。数组的所有元素都具有相同的类型
。let my_array: [i32; 5] = [1, 2, 3, 4, 5];
在 Rust 中,你可以使用索引值来访问数组中的特定元素。数组的索引同样从 0 开始,即第一个元素的索引是 0,第二个元素的索引是 1,以此类推。以下是一个简单的示例:
let my_array: [i32; 5] = [1, 2, 3, 4, 5];// 访问第一个元素
let first_element = my_array[0];
println!("First element: {}", first_element); // 输出: First element: 1// 访问第三个元素
let third_element = my_array[2];
println!("Third element: {}", third_element); // 输出: Third element: 3
数组的长度也是固定的 因此定义长度之后必须要把值填满,否则会报错哦
整数类型技术细节
在 Rust 中,整数溢出是指当一个整数的值超出了其所能表示的范围时发生的情况。Rust 提供了多种方式来处理整数溢出,包括检查溢出、panic on overflow 和使用 Wrapping 模式。下面我将详细介绍这些方式,并提供相应的示例代码。
1. 检查溢出(Checking Overflow)
在 Rust 中,可以使用 checked_add
、checked_sub
、checked_mul
等方法来检查整数加法、减法、乘法是否会导致溢出。这些方法返回一个 Option
类型,如果计算结果在整数类型能表示的范围内,则返回 Some
,否则返回 None
。
示例代码:
fn main() {let x: i32 = 2147483647;let y = x.checked_add(1); // 检查加法溢出match y {Some(result) => println!("Result: {}", result),None => println!("Overflow occurred!"),}
}
2. 溢出时 panic(Panic on Overflow)
如果希望在发生溢出时立即停止程序并产生 panic,可以使用 overflowing_add
、overflowing_sub
、overflowing_mul
等方法。这些方法返回一个元组,其中第一个元素是计算结果,第二个元素是一个布尔值,表示是否发生了溢出。
示例代码:
fn main() {let x: i32 = 2147483647;let (result, overflow) = x.overflowing_add(1); // 检查加法溢出if overflow {panic!("Overflow occurred!");} else {println!("Result: {}", result);}
}
3. 使用 Wrapping 模式(Wrapping Behavior)
如果希望在发生溢出时按照模运算的方式处理,可以使用 wrapping_add
、wrapping_sub
、wrapping_mul
等方法。这些方法会对溢出的部分进行截断,并返回一个包装过的结果。
示例代码:
fn main() {let x: i32 = 2147483647;let result = x.wrapping_add(1); // 检查加法溢出println!("Result: {}", result); // 结果会是 -2147483648
}