标量(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); }
复合类型可以将多个值组合成一个类型。Rust有两种基本的复合类型:元组和数组。
元组是将多个不同类型的值组合在一起的复合类型。元组有固定的长度。
// 创建元组 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;
数组是每个元素类型相同、长度固定的集合。
// 创建数组 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);
Rust不允许隐式类型转换,必须使用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
use std::convert::TryInto; let a: i32 = 300; let b: Result<u8, _> = a.try_into(); match b { Ok(v) => println!("转换成功:{}", v), Err(e) => println!("转换失败:{}", e), }
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<i32>
显式标注的必要情况:
// 多种可能时 let guess: u32 = "42".parse().expect("不是数字!"); // 函数参数和返回值 fn add(x: i32, y: i32) -> i32 { x + y }
使用type关键字创建类型别名:
type Kilometers = i32; type Thunk = Box<dyn Fn() + Send + 'static>; let x: i32 = 5; let y: Kilometers = 5; println!("x + y = {}", x + y); // 可以相加,因为是同一类型
Never类型表示永远不会返回的函数:
fn panic_now() -> ! { panic!("这个函数永远不会正常返回"); } fn infinite_loop() -> ! { loop { println!("永远循环"); } }
实现摄氏度、华氏度和开尔文温度的相互转换。
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)); }
计算数组的均值、最大值和最小值。
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); }
交换元组中两个元素的位置。
fn swap_tuple<T, U>(t: (T, U)) -> (U, T) { (t.1, t.0) } fn main() { let pair = ("hello", 42); let swapped = swap_tuple(pair); println!("原元组:{:?}", pair); println!("交换后:{:?}", swapped); }
检查一个数是否为素数。
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!(); }
将十进制数转换为二进制、八进制和十六进制字符串。
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的基本数据类型:
掌握这些基本类型是编写Rust程序的基础。在下一章中,我们将学习Rust的控制流结构。