概述

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 有两种浮点类型:f32f64(默认)。

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);
}

布尔类型

布尔类型只有两个值:truefalse

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 的数据类型:

  1. 标量类型

    • 整数类型:i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
    • 浮点类型:f32, f64
    • 布尔类型:bool
    • 字符类型:char
  2. 复合类型

    • 元组:固定长度,可以包含不同类型
    • 数组:固定长度,所有元素类型相同
    • 向量:动态数组,长度可变
    • 字符串:String&str
    • 哈希映射:存储键值对
  3. 类型转换

    • Rust 不支持隐式类型转换
    • 使用 as 关键字进行显式转换
  4. 类型推断

    • 编译器可以根据上下文推断类型
    • 必要时需要显式类型注解

下一步

在下一教程中,我们将学习 Rust 的控制流,包括:

  • match 表达式

  • if letwhile let

  • 更复杂的循环模式

继续学习 Rust,掌握这门强大语言的更多特性!