Rust 数据类型详解
概述
Rust 是一门静态类型语言,这意味着在编译时必须知道所有变量的类型。Rust 的类型系统非常强大,能够帮助我们在编译时捕获许多错误。
Rust 的数据类型可以分为两大类:
-
标量类型(Scalar):单个值
-
复合类型(Compound):多个值的组合
标量类型
整数类型
整数是没有小数部分的数字。Rust 提供了多种整数类型,可以根据需要选择:
| 长度 | 有符号 | 无符号 |
|---|---|---|
| 8-bit | i8 |
u8 |
| 16-bit | i16 |
u16 |
| 32-bit | i32 |
u32 |
| 64-bit | i64 |
u64 |
| 128-bit | i128 |
u128 |
| arch | isize |
usize |
整数类型示例
fn main() {
// 有符号整数
let small: i8 = 127; // -128 到 127
let medium: i32 = 5000; // 默认类型
let large: i64 = 1_000_000;
let huge: i128 = 170141183460469231731687303715884105727;
// 无符号整数
let byte: u8 = 255; // 0 到 255
let unsigned: u32 = 100;
// 平台相关类型
let pointer_size: usize = 64; // 在 64 位系统上
let signed_size: isize = -64;
// 整数字面量
let decimal = 98_222; // 十进制
let hex = 0xff; // 十六进制
let octal = 0o77; // 八进制
let binary = 0b1111_0000; // 二进制
let byte_literal = b'A'; // 字节字面量
println!("有符号: {}, {}, {}, {}", small, medium, large, huge);
println!("无符号: {}, {}", byte, unsigned);
println!("平台相关: {}, {}", pointer_size, signed_size);
println!("字面量: {}, {}, {}, {}, {}", decimal, hex, octal, binary, byte_literal);
}
整数溢出
fn main() {
// 在 debug 模式下,整数溢出会导致 panic
// 在 release 模式下,会进行回绕(wrapping)
let mut x: u8 = 255;
// x = x + 1; // debug 模式下会 panic
// 显式处理溢出
let x = x.wrapping_add(1); // 0
println!("wrapping_add: {}", x);
let x = x.checked_add(255); // None
println!("checked_add: {:?}", x);
let x = x.saturating_add(255); // 255
println!("saturating_add: {}", x);
let x = x.overflowing_add(1); // (0, true)
println!("overflowing_add: {:?}", x);
}
浮点类型
Rust 有两种浮点类型:f32 和 f64(默认)。
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
// 浮点运算
let sum = x + y as f64;
let difference = x - y as f64;
let product = x * y as f64;
let quotient = x / y as f64;
let remainder = x % y as f64;
println!("加法: {}", sum);
println!("减法: {}", difference);
println!("乘法: {}", product);
println!("除法: {}", quotient);
println!("取余: {}", remainder);
// 浮点数比较
let abs_difference = (x - y as f64).abs();
println!("绝对差值: {}", abs_difference);
}
布尔类型
布尔类型只有两个值:true 和 false。
fn main() {
let t = true;
let f: bool = false;
// 布尔运算
let and = t && f;
let or = t || f;
let not = !t;
println!("t && f = {}", and);
println!("t || f = {}", or);
println!("!t = {}", not);
// 在控制流中使用
if t {
println!("条件为真");
}
}
字符类型
Rust 的 char 类型是 Unicode 标量值,占用 4 字节。
fn main() {
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
println!("字符: {}, {}, {}", c, z, heart_eyed_cat);
// 字符方法
println!("'z' 的 Unicode 值: {}", 'z' as u32);
println!("'😻' 的 Unicode 值: {}", '😻' as u32);
// 字符分类
let digit = '7';
println!("'{}' 是数字: {}", digit, digit.is_digit(10));
println!("'{}' 是字母: {}", c, c.is_alphabetic());
println!("'{}' 是小写: {}", c, c.is_lowercase());
println!("'{}' 是大写: {}", z, z.is_uppercase());
}
复合类型
元组(Tuple)
元组可以将多个不同类型的值组合在一起。元组一旦声明,长度就固定了。
fn main() {
// 创建元组
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解构元组
let (x, y, z) = tup;
println!("x = {}, y = {}, z = {}", x, y, z);
// 通过索引访问
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = tup.2;
println!("tup.0 = {}, tup.1 = {}, tup.2 = {}", five_hundred, six_point_four, one);
// 单元素元组
let single = (5,); // 注意逗号
println!("单元素元组: {:?}", single);
// 空元组(单元类型)
let unit = ();
println!("空元组: {:?}", unit);
}
数组(Array)
数组中的所有元素必须是相同的类型,且长度固定。
fn main() {
// 创建数组
let a = [1, 2, 3, 4, 5];
// 指定类型和长度
let b: [i32; 5] = [1, 2, 3, 4, 5];
// 创建包含相同值的数组
let c = [3; 5]; // [3, 3, 3, 3, 3]
println!("数组 a: {:?}", a);
println!("数组 b: {:?}", b);
println!("数组 c: {:?}", c);
// 访问数组元素
let first = a[0];
let second = a[1];
println!("第一个元素: {}", first);
println!("第二个元素: {}", second);
// 遍历数组
println!("遍历数组:");
for element in a.iter() {
println!(" {}", element);
}
// 带索引遍历
println!("带索引遍历:");
for (i, &element) in a.iter().enumerate() {
println!(" 索引 {}: {}", i, element);
}
// 数组长度
println!("数组长度: {}", a.len());
// 数组切片
let slice = &a[1..4];
println!("切片 [1..4]: {:?}", slice);
}
向量(Vector)
向量是动态数组,长度可以变化。
fn main() {
// 创建空向量
let mut v: Vec<i32> = Vec::new();
// 使用宏创建
let v2 = vec![1, 2, 3];
// 添加元素
v.push(5);
v.push(6);
v.push(7);
v.push(8);
println!("向量 v: {:?}", v);
println!("向量 v2: {:?}", v2);
// 读取元素
let third: &i32 = &v[2];
println!("第三个元素: {}", third);
// 使用 get 方法(更安全)
match v.get(2) {
Some(third) => println!("第三个元素: {}", third),
None => println!("没有第三个元素"),
}
// 遍历向量
println!("遍历向量:");
for i in &v {
println!(" {}", i);
}
// 可变遍历
println!("修改向量元素:");
for i in &mut v {
*i *= 2;
}
println!("修改后的向量: {:?}", v);
// 向量长度和容量
println!("长度: {}, 容量: {}", v.len(), v.capacity());
}
字符串(String)
Rust 的字符串类型比较复杂,主要有 String 和 &str 两种。
fn main() {
// 创建空字符串
let mut s = String::new();
// 从字面量创建
let s1 = String::from("hello");
let s2 = "world".to_string();
// 添加字符串
s.push_str("hello");
s.push('!');
println!("字符串 s: {}", s);
println!("字符串 s1: {}", s1);
println!("字符串 s2: {}", s2);
// 字符串拼接
let s3 = s1 + &s2;
println!("拼接后: {}", s3);
// 使用 format! 宏
let s4 = format!("{}-{}-{}", s, s1, s2);
println!("格式化: {}", s4);
// 字符串长度(字节数)
println!("字符串长度: {}", s4.len());
// 遍历字符
println!("遍历字符:");
for c in s4.chars() {
println!(" {}", c);
}
// 遍历字节
println!("遍历字节:");
for b in s4.bytes() {
println!(" {}", b);
}
// 字符串切片
let hello = "Здравствуйте";
let s = &hello[0..4];
println!("字符串切片: {}", s);
}
哈希映射(HashMap)
HashMap 存储键值对。
use std::collections::HashMap;
fn main() {
// 创建 HashMap
let mut scores = HashMap::new();
// 插入键值对
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
println!("HashMap: {:?}", scores);
// 从元组创建
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores2: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect();
println!("HashMap2: {:?}", scores2);
// 访问值
let team_name = String::from("Blue");
let score = scores.get(&team_name);
match score {
Some(s) => println!("Blue 队的分数: {}", s),
None => println!("没有找到 Blue 队"),
}
// 遍历 HashMap
println!("遍历 HashMap:");
for (key, value) in &scores {
println!(" {}: {}", key, value);
}
// 更新值
scores.insert(String::from("Blue"), 25); // 覆盖
println!("更新后: {:?}", scores);
// 只在键不存在时插入
scores.entry(String::from("Yellow")).or_insert(100);
println!("or_insert 后: {:?}", scores);
// 根据旧值更新
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("单词计数: {:?}", map);
}
类型转换
隐式类型转换
Rust 不支持隐式类型转换,必须显式转换。
fn main() {
let integer = 5;
let float = 5.0;
// 错误:不能隐式转换
// let sum = integer + float;
// 正确:显式转换
let sum = integer as f64 + float;
println!("和: {}", sum);
}
显式类型转换
fn main() {
let integer = 5;
let float = 5.0;
// 整数转浮点数
let float_from_int = integer as f64;
println!("整数转浮点数: {}", float_from_int);
// 浮点数转整数(会截断)
let int_from_float = float as i32;
println!("浮点数转整数: {}", int_from_float);
// 字符转整数
let c = 'A';
let int_from_char = c as u32;
println!("字符转整数: {}", int_from_char);
// 整数转字符(必须在有效范围内)
let char_from_int = 65u8 as char;
println!("整数转字符: {}", char_from_int);
}
类型推断
Rust 的编译器可以根据上下文推断类型。
fn main() {
// 编译器推断为 i32
let x = 5;
// 编译器推断为 f64
let y = 5.0;
// 需要类型注解
let sum = x + 10i32;
// 使用类型注解
let z: i64 = 100;
println!("x: {}, y: {}, sum: {}, z: {}", x, y, sum, z);
}
总结
本教程详细介绍了 Rust 的数据类型:
-
标量类型:
- 整数类型:
i8,i16,i32,i64,i128,isize,u8,u16,u32,u64,u128,usize - 浮点类型:
f32,f64 - 布尔类型:
bool - 字符类型:
char
- 整数类型:
-
复合类型:
- 元组:固定长度,可以包含不同类型
- 数组:固定长度,所有元素类型相同
- 向量:动态数组,长度可变
- 字符串:
String和&str - 哈希映射:存储键值对
-
类型转换:
- Rust 不支持隐式类型转换
- 使用
as关键字进行显式转换
-
类型推断:
- 编译器可以根据上下文推断类型
- 必要时需要显式类型注解
下一步
在下一教程中,我们将学习 Rust 的控制流,包括:
-
match表达式 -
if let和while let -
更复杂的循环模式
继续学习 Rust,掌握这门强大语言的更多特性!

