====== 第三章 基本数据类型 ======
===== 3.1 标量类型 =====
标量(Scalar)类型代表单个值。Rust有四种主要的标量类型:整数、浮点数、布尔值和字符。
==== 整数类型 =====
整数是没有小数部分的数字。
**有符号整数(可正可负):**
| 类型 | 范围 | 大小 |
|------|------|------|
| i8 | -128 到 127 | 1字节 |
| i16 | -32,768 到 32,767 | 2字节 |
| i32 | -2,147,483,648 到 2,147,483,647 | 4字节 |
| i64 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 | 8字节 |
| i128 | 非常大的范围 | 16字节 |
| isize | 取决于架构(32位或64位) | 4或8字节 |
**无符号整数(仅非负):**
| 类型 | 范围 | 大小 |
|------|------|------|
| u8 | 0 到 255 | 1字节 |
| u16 | 0 到 65,535 | 2字节 |
| u32 | 0 到 4,294,967,295 | 4字节 |
| u64 | 0 到 18,446,744,073,709,551,615 | 8字节 |
| u128 | 非常大的范围 | 16字节 |
| usize | 取决于架构 | 4或8字节 |
**整数溢出:**
在debug模式下,整数溢出会导致panic;在release模式下,会进行二进制补码环绕。
let mut x: u8 = 255;
// x = x + 1; // debug模式panic,release模式变为0
// 显式处理溢出
let (result, overflowed) = x.overflowing_add(1);
println!("结果:{},溢出:{}", result, overflowed);
**整数方法:**
let n = 42_i32;
// 检查奇偶
println!("是偶数:{}", n.is_even());
// 转换类型
let n_u8 = n as u8;
// 计数位数
println!("二进制中1的个数:{}", n.count_ones());
// 绝对值
let m = -42;
println!("绝对值:{}", m.abs());
// 幂运算
println!("2的10次方:{}", 2_i32.pow(10));
==== 浮点类型 ====
Rust有两种浮点类型:f32(单精度)和f64(双精度)。
let x = 2.0; // f64(默认)
let y: f32 = 3.0; // f32
**浮点运算:**
// 基本运算
let sum = 5.0 + 10.0;
let difference = 95.5 - 4.3;
let product = 4.0 * 30.0;
let quotient = 56.7 / 32.2;
let remainder = 43.0 % 5.0;
// 数学函数
let sqrt = 4.0_f64.sqrt();
let power = 2.0_f64.powf(3.0); // 2的3次方
let log = 100.0_f64.log10(); // 以10为底的对数
let floor = 3.7_f64.floor();
let ceil = 3.2_f64.ceil();
let round = 3.5_f64.round();
**特殊浮点值:**
let inf = f64::INFINITY;
let neg_inf = f64::NEG_INFINITY;
let nan = f64::NAN;
// 检查
println!("是正无穷:{}", inf.is_infinite());
println!("是NaN:{}", nan.is_nan());
==== 布尔类型 ====
let t = true;
let f: bool = false;
// 逻辑运算
let and = t && f; // 逻辑与
let or = t || f; // 逻辑或
let not = !t; // 逻辑非
布尔类型占用1字节。
==== 字符类型 ====
Rust的char类型是Unicode标量值,占用4字节。
let c = 'z';
let z: char = 'ℤ';
let heart_eyed_cat = '😻';
let chinese = '中';
**字符方法:**
let c = 'A';
println!("是大写字母:{}", c.is_uppercase());
println!("是小写字母:{}", c.is_lowercase());
println!("是字母:{}", c.is_alphabetic());
println!("是数字:{}", c.is_numeric());
println!("是空白字符:{}", c.is_whitespace());
// 大小写转换
println!("小写:{}", c.to_lowercase());
println!("大写:{}", 'a'.to_uppercase());
// 转换为数字
let num_char = '9';
if let Some(digit) = num_char.to_digit(10) {
println!("数字值:{}", digit);
}
===== 3.2 复合类型 =====
复合类型可以将多个值组合成一个类型。Rust有两种基本的复合类型:元组和数组。
==== 元组(Tuple) ====
元组是将多个不同类型的值组合在一起的复合类型。元组有固定的长度。
// 创建元组
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 类型推断
let tup = (500, 6.4, 1);
// 解构
let (x, y, z) = tup;
println!("y的值为:{}", y);
// 通过索引访问
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = tup.2;
**单元类型(Unit Type):**
let unit = (); // 空元组,表示"无返回值"
**嵌套元组:**
let nested = ((1, 2), (3, 4, 5));
let ((a, b), (c, d, e)) = nested;
==== 数组(Array) ====
数组是每个元素类型相同、长度固定的集合。
// 创建数组
let a = [1, 2, 3, 4, 5];
let months = ["January", "February", "March"];
// 指定类型和长度
let a: [i32; 5] = [1, 2, 3, 4, 5];
// 重复值初始化
let a = [3; 5]; // [3, 3, 3, 3, 3]
// 访问元素
let first = a[0];
let second = a[1];
**数组越界:**
let a = [1, 2, 3, 4, 5];
// let index = 10;
// let element = a[index]; // 运行时panic!
Rust会在运行时检查数组索引,越界访问会导致程序panic。
**数组方法:**
let mut arr = [3, 1, 4, 1, 5];
// 长度
println!("长度:{}", arr.len());
// 排序
arr.sort();
println!("排序后:{:?}", arr);
// 反转
arr.reverse();
// 填充
arr.fill(0);
// 查找
let pos = arr.iter().position(|&x| x == 0);
===== 3.3 类型转换 =====
Rust不允许隐式类型转换,必须使用as关键字显式转换。
==== as关键字 ====
let x: i32 = 42;
let y: i64 = x as i64; // i32转i64
let a: f64 = 3.14;
let b: i32 = a as i32; // 浮点转整数,截断小数部分
let c: u8 = 255;
let d: i8 = c as i8; // 溢出,变成-1
==== try_into转换(安全转换) ====
use std::convert::TryInto;
let a: i32 = 300;
let b: Result = a.try_into();
match b {
Ok(v) => println!("转换成功:{}", v),
Err(e) => println!("转换失败:{}", e),
}
===== 3.4 类型推断 =====
Rust编译器可以根据上下文推断变量类型:
let x = 5; // 推断为i32
let y = 3.14; // 推断为f64
let z = true; // 推断为bool
let s = "hello"; // 推断为&str
let v = vec![1, 2, 3]; // 推断为Vec
**显式标注的必要情况:**
// 多种可能时
let guess: u32 = "42".parse().expect("不是数字!");
// 函数参数和返回值
fn add(x: i32, y: i32) -> i32 {
x + y
}
===== 3.5 类型别名 =====
使用type关键字创建类型别名:
type Kilometers = i32;
type Thunk = Box;
let x: i32 = 5;
let y: Kilometers = 5;
println!("x + y = {}", x + y); // 可以相加,因为是同一类型
===== 3.6 Never类型(!)=====
Never类型表示永远不会返回的函数:
fn panic_now() -> ! {
panic!("这个函数永远不会正常返回");
}
fn infinite_loop() -> ! {
loop {
println!("永远循环");
}
}
===== 练习题 =====
==== 练习题3.1:温度转换器 ====
实现摄氏度、华氏度和开尔文温度的相互转换。
fn celsius_to_fahrenheit(c: f64) -> f64 {
c * 9.0 / 5.0 + 32.0
}
fn fahrenheit_to_celsius(f: f64) -> f64 {
(f - 32.0) * 5.0 / 9.0
}
fn celsius_to_kelvin(c: f64) -> f64 {
c + 273.15
}
fn main() {
let c = 100.0;
println!("{}°C = {:.2}°F", c, celsius_to_fahrenheit(c));
println!("{}°C = {:.2}K", c, celsius_to_kelvin(c));
}
==== 练习题3.2:数组统计 ====
计算数组的均值、最大值和最小值。
fn array_stats(arr: &[i32]) -> (f64, i32, i32) {
if arr.is_empty() {
return (0.0, 0, 0);
}
let sum: i32 = arr.iter().sum();
let mean = sum as f64 / arr.len() as f64;
let max = *arr.iter().max().unwrap();
let min = *arr.iter().min().unwrap();
(mean, max, min)
}
fn main() {
let numbers = [23, 56, 12, 89, 34, 67, 45];
let (mean, max, min) = array_stats(&numbers);
println!("数组:{:?}", numbers);
println!("平均值:{:.2}", mean);
println!("最大值:{}", max);
println!("最小值:{}", min);
}
==== 练习题3.3:元组交换 ====
交换元组中两个元素的位置。
fn swap_tuple(t: (T, U)) -> (U, T) {
(t.1, t.0)
}
fn main() {
let pair = ("hello", 42);
let swapped = swap_tuple(pair);
println!("原元组:{:?}", pair);
println!("交换后:{:?}", swapped);
}
==== 练习题3.4:素数检查 ====
检查一个数是否为素数。
fn is_prime(n: u32) -> bool {
if n <= 1 {
return false;
}
if n <= 3 {
return true;
}
if n % 2 == 0 || n % 3 == 0 {
return false;
}
let mut i = 5;
while i * i <= n {
if n % i == 0 || n % (i + 2) == 0 {
return false;
}
i += 6;
}
true
}
fn main() {
for n in 1..=100 {
if is_prime(n) {
print!("{} ", n);
}
}
println!();
}
==== 练习题3.5:进制转换 ====
将十进制数转换为二进制、八进制和十六进制字符串。
fn to_binary(n: u32) -> String {
format!("{:b}", n)
}
fn to_octal(n: u32) -> String {
format!("{:o}", n)
}
fn to_hex(n: u32) -> String {
format!("{:X}", n)
}
fn main() {
let n = 255;
println!("十进制:{}", n);
println!("二进制:{}", to_binary(n));
println!("八进制:{}", to_octal(n));
println!("十六进制:{}", to_hex(n));
}
===== 本章小结 =====
本章详细介绍了Rust的基本数据类型:
* **整数类型**:i8-i128, u8-u128, isize, usize
* **浮点类型**:f32, f64
* **布尔类型**:true, false
* **字符类型**:Unicode标量值,4字节
* **元组**:固定长度,可包含不同类型,通过.索引访问
* **数组**:固定长度,元素类型相同,索引访问
* **类型转换**:使用as关键字或try_into
掌握这些基本类型是编写Rust程序的基础。在下一章中,我们将学习Rust的控制流结构。