Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第2章:变量、数据类型与控制流

学习目标

  • 掌握 Rust 中变量声明和使用的基本语法
  • 理解各种数据类型的特性和使用场景
  • 熟练使用控制流语句进行逻辑控制
  • 学会定义和调用函数

2.1 变量与可变性

2.1.1 基本变量声明

在 Rust 中,变量通过 let 关键字声明,默认是不可变的(immutable)。这意味着一旦变量被绑定到一个值,你就不能再修改它。这种设计是为了确保代码的安全性和可预测性,避免意外的副作用。Rust 的类型系统会自动推断变量的类型,但你也可以显式指定(如 let x: i32 = 5;)。

#![allow(unused)]
fn main() {
// 基本变量声明(不可变)
fn variable_basics() {
    let x = 42;                    // 整数
    let y = 3.14;                  // 浮点数
    let name = "Rust";             // 字符串字面量
    let is_rust_awesome = true;    // 布尔值
    
    println!("整数: {}", x);
    println!("浮点数: {}", y);
    println!("字符串: {}", name);
    println!("布尔值: {}", is_rust_awesome);
    
    // 变量遮蔽(shadowing)
    let x = x + 10;                // 创建新的 x,原 x 被隐藏
    {
        let x = "shadowed";       // 创建新的 x,原 x 被隐藏
        println!("遮蔽中的 x: {}", x);
    }
    println!("遮蔽后的 x: {}", x);
}
}

Result:

整数: 42
浮点数: 3.14
字符串: Rust
布尔值: true
遮蔽中的 x: shadowed
遮蔽后的 x: 52

关键点

  • 使用 let 绑定值。
  • 变量名区分大小写,遵循蛇形命名法(snake_case)。
  • 在函数或块作用域内有效,超出作用域后自动释放(所有权系统)。

2.1.2 可变变量

Rust 的默认不可变性很严格,但如果你需要修改变量,可以使用 mut 关键字声明为可变的(mutable)。这允许你重新赋值,但必须在声明时就指定,以明确意图。注意,可变性是作用域内的:一个变量在整个作用域内要么可变,要么不可变,不能中途改变。

#![allow(unused)]
fn main() {
fn mutable_variables() {
    // 可变变量声明
    let mut counter = 0;
    println!("初始值: {}", counter);
    
    // 修改可变变量
    counter += 1;
    counter *= 2;
    println!("修改后: {}", counter);
    
    // 可变变量的典型用途
    let mut sum = 0;  // 初始化为 0
    let numbers = vec![1, 2, 3, 4, 5];  // 创建一个向量
    
    for num in numbers {
        sum += num;                // 在循环中累积计算
    }
    
    println!("数列和: {}", sum);
}
}

Result:

初始值: 0
修改后: 2
数列和: 15

关键点

  • 使用 let mut 声明可变变量。
  • 可变变量可以在声明后重新赋值。
  • 可变变量在循环或函数中常用,以累积计算结果。
  • 可变变量在 Rust 中是谨慎使用的,以避免意外修改。
  • 只在需要时使用 mut,以最小化可变性(减少 bug 风险)。
  • 在借用规则下,可变借用(&mut)有严格限制,确保线程安全。
  • 作用域内,变量要么可变,要么不可变,不能中途改变。

可变变量是 Rust 灵活性的关键,但结合所有权和借用检查器,使用时需小心避免编译错误。

2.1.3 常量声明

常量通过 const 关键字声明,是不可变的,且必须在编译时确定值(不能是运行时计算的)。常量是全局可见的(如果在模块顶层声明),并在整个程序生命周期内有效。它们适合定义不变的配置或数学常数。类型必须显式指定,且不能是 mut

#![allow(unused)]
fn main() {
// 常量声明(always immutable, must have type annotation)
fn constants_example() {
    const PI: f64 = 3.14159265359;  // 浮点数常量
    const MAX_SIZE: usize = 1000; // 无符号整数常量
    const GREETING: &str = "Hello, World!"; // 字符串常量
    
    println!("PI = {}", PI);
    println!("最大尺寸: {}", MAX_SIZE);
    println!("问候语: {}", GREETING);
    
    // 常量表达式
    const AREA: f64 = PI * 10.0 * 10.0;  // 圆面积公式
    println!("圆面积: {}", AREA);
}
}

Result:

PI = 3.14159265359
最大尺寸: 1000
问候语: Hello, World!
圆面积: 314.15926535899996

关键点

  • 使用 const NAME: Type = value; 格式,NAME 遵循大写蛇形命名(SCREAMING_SNAKE_CASE)。
  • 值必须是常量表达式(如字面量、简单计算),不能依赖运行时输入。
  • 静态常量(static)类似,但有额外生命周期考虑;const 更常见用于简单值。
  • 常量在编译时确定,提升代码的可维护性和性能。
  • 常量不可变,适用于定义不变的事实或配置。

常量提升了代码的可维护性,因为它们是不可变的“事实”,并在编译时优化。


2.2 基础数据类型

Rust 的基础数据类型分为标量类型(scalar types)和复合类型(compound types)。标量类型表示单一值,复合类型可包含多个值。这些类型在编译时确定大小,确保内存安全和性能。

标量类型(Scalars)

  • 整数(Integers):有符号(i8, i16, i32, i64, isize)和无符号(u8, u16, u32, u64, usize)。默认 i32。
  • 浮点数(Floats):f32(单精度)和 f64(双精度,默认)。
  • 布尔(Boolean):bool,仅 true 或 false。
  • 字符(Character):char,Unicode 标量值(如 'a')。

复合类型(Compounds)

  • 元组(Tuples):固定大小的异构集合,如 (i32, bool)
  • 数组(Arrays):固定长度、同构元素,如 [i32; 5](5 个 i32)。

2.2.1 整数类型

#![allow(unused)]
fn main() {
fn integer_types() {
    // 有符号整数
    let i8_val: i8 = -128;          // 范围: -128 到 127 
    let i16_val: i16 = -32768;      // 范围: -32768 到 32767
    let i32_val: i32 = -2147483648; // 默认的整数类型
    let i64_val: i64 = -9223372036854775808;
    let i128_val: i128 = -170141183460469231731687303715884105728;
    
    // 无符号整数
    let u8_val: u8 = 255;           // 范围: 0 到 255
    let u16_val: u16 = 65535;
    let u32_val: u32 = 4294967295;
    let u64_val: u64 = 18446744073709551615;
    let u128_val: u128 = 340282366920938463463374607431768211455;
    
    // 平台相关整数类型
    let isize: isize = -1;          // 平台相关大小
    let usize: usize = 1;           // 平台相关大小
    
    // 数值字面量
    let decimal = 98_222;           // 十进制(可用下划线分隔)
    let hex = 0xff;                 // 十六进制
    let octal = 0o77;               // 八进制
    let binary = 0b1111_0000;       // 二进制
    let byte = b'A';                // 字节字符(仅 u8)
    
    println!("整数值: {}, {}, {}, {}", decimal, hex, octal, binary);
}
}

Result:

整数值: 98222, 255, 63, 240

关键点:

  • Rust 中的整数类型有符号和无符号,有符号整数可以表示负数,无符号整数只能表示非负数。
  • Rust 提供了多种整数类型,包括 8 位、16 位、32 位、64 位和 128 位的有符号和无符号整数。
  • Rust 还提供了平台相关的整数类型,如 isizeusize,它们的大小取决于运行程序的计算机架构。
  • Rust 支持数值字面量的多种表示方式,包括十进制、十六进制、八进制和二进制。
  • Rust 中的整数类型都有固定的范围,超过范围会导致溢出错误。
  • Rust 提供了 std::num 模块中的函数来处理整数溢出,如 wrapping_addwrapping_subwrapping_mul 等。
  • ...

2.2.2 浮点类型

#![allow(unused)]
fn main() {
fn float_types() {
    let f32_val: f32 = 3.141592653589793; // 32位浮点
    let f64_val: f64 = 3.141592653589793; // 64位浮点(默认)

    // 特殊值
    let infinity = f32::INFINITY;
    let neg_infinity = f32::NEG_INFINITY;
    let not_a_number = f32::NAN;

    println!("f32: {}", f32_val);
    println!("f64: {}", f64_val);
    println!("无穷大: {}", infinity);
    println!("负无穷大: {}", neg_infinity);
    println!("非数字: {}", not_a_number);

    // 数学运算
    let result = f32::sqrt(2.0);
    println!("√2 = {}", result);

    // 比较运算
    let x: f64 = 1.0;   //必须显式声明类型,否则编译器无法推断
    let y: f64 = 0.1 + 0.1 + 0.1 + 0.1 + 0.1; //必须显式声明类型,否则编译器无法推断
    println!("x == y: {}", x == y); // 避免直接比较浮点数
    println!("(x - y).abs() < 1e-10: {}", (x - y).abs() < 1e-10);
}
}

Result:

f32: 3.1415927
f64: 3.141592653589793
无穷大: inf
负无穷大: -inf
非数字: NaN
√2 = 1.4142135
x == y: false
(x - y).abs() < 1e-10: false

关键点:

  • Rust 提供了两种浮点类型:f32 和 f64,分别占用 32 位和 64 位内存。
  • 浮点数可以表示特殊值,如无穷大、负无穷大和非数字(NaN)。
  • 浮点数运算可能会产生不精确的结果,因此建议避免直接比较浮点数,而是比较它们的差值是否在可接受范围内。
  • 浮点数运算符包括加法(+)、减法(-)、乘法(*)、除法(/)和取余(%)。
  • 浮点数函数包括平方根(sqrt)、指数(exp)、对数(log)、三角函数等。
  • 浮点数类型可以与整数类型进行混合运算,但结果类型将自动提升为浮点数类型。
  • 浮点数类型可以与布尔类型进行混合运算,但结果类型将自动提升为布尔类型。
  • 浮点数类型可以与字符串类型进行混合运算,但结果类型将自动提升为字符串类型。
  • ...

2.2.3 布尔类型

#![allow(unused)]
fn main() {
fn boolean_types() {
    let is_learning_rust = true;
    let is_difficult = false;

    // 条件表达式
    let message = if is_learning_rust {
        "Keep going!"
    } else {
        "Try harder!"
    };

    // 布尔逻辑
    let both_true = is_learning_rust && !is_difficult;
    let either_or = is_learning_rust || is_difficult;

    println!("{} {}", message, both_true);
    println!("Either learning or difficult: {}", either_or);

    // 模式匹配中的布尔
    match (is_learning_rust, is_difficult) {
        (true, false) => println!("Perfect learning situation!"),
        (true, true) => println!("Challenging but rewarding!"),
        (false, _) => println!("Maybe try something else?"),
    }
}
}

Result:

Keep going! true
Either learning or difficult: true
Perfect learning situation!

关键点:

  • 布尔类型只有两个值:true 和 false。
  • 布尔类型可以与整数类型进行混合运算,但结果类型将自动提升为整数类型。
  • 布尔类型可以与字符串类型进行混合运算,但结果类型将自动提升为字符串类型。

2.2.4 字符类型

Rust 中的“字符”指的是 Unicode 标量值(Unicode scalar value),通过 chars() 方法获取。它不是固定大小的字节,而是逻辑上的字符单位。

字符需要使用单引号包裹,并且只能表示一个字符。 字符串底层是字节数组([u8]),可以通过 as_bytes() 获取视图。

注意 :字节操作高效,但需小心:切片字节可能截断字符,导致无效 UTF-8。

#![allow(unused)]
fn main() {
fn character_types() {
    let c1 = 'z';                          // 单个字符
    let c2 = 'ℤ';                          // Unicode 字符
    let c3 = '😊';                         // 表情符号
    
    println!("字符: {}, {}, {}", c1, c2, c3);
    
    // 转义字符
    let newline = '\n';
    let tab = '\t';
    let quote = '\'';
    let backslash = '\\';
    
    // 字符串中的字符
    let string = "Hello, 世界! 🌍";
    for (index, char) in string.chars().enumerate() {
        println!("字符 {}: {}", index, char);
    }
    
    // 获取字节
    let bytes = string.as_bytes();
    println!("字符串长度(字节): {}", bytes.len());
}
}

Result:

字符: z, ℤ, 😊
字符 0: H
字符 1: e
字符 2: l
字符 3: l
字符 4: o
字符 5: ,
字符 6:
字符 7: 世
字符 8: 界
字符 9: !
字符 10:
字符 11: 🌍
字符串长度(字节): 19

关键点:

  • 字符类型是 Unicode 标量值,可以表示任何字符。
  • 字符串是字节数组,可以通过 as_bytes() 获取字节视图。
  • 字符串中的字符可以通过 chars() 方法获取,并使用 enumerate() 方法遍历。
  • 字符串长度是字节长度,而不是字符长度。
  • 字符串中的字符可能被截断,导致无效 UTF-8。
  • 字符串中的字符可以通过 chars() 方法获取,并使用 enumerate() 方法遍历。
  • ...

2.3 复合数据类型:元组和数组

2.3.1 元组(Tuple)

元组是固定长度的有序集合,可以包含不同类型的元素。创建后长度不可变,但内部元素可以是非同质的。

元组基础操作

#![allow(unused)]
fn main() {
fn tuple_basics() {
    // 创建元组
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    let tup2 = (42, "Hello", true);
    
    // 访问元组元素(使用索引)
    let x = tup.0;  // 500
    let y = tup.1;  // 6.4
    let z = tup.2;  // 1
    
    println!("元组值: ({}, {}, {})", x, y, z);
    
    // 解构赋值(模式匹配)
    let (a, b, c) = tup;
    println!("解构后的值: a={}, b={}, c={}", a, b, c);
    
    // 单个元素的元组(注意逗号)
    let single_tuple: (i32,) = (5,);
    let single_value = single_tuple.0;
    println!("单个元素元组: ({}, {})", single_value, single_tuple.0);
}
}

Result:

元组值: (500, 6.4, 1)
解构后的值: a=500, b=6.4, c=1
单个元素元组: (5, 5)

关键点:

  • 元组是固定长度的有序集合,可以包含不同类型的元素。
  • 元组可以通过索引访问元素,索引从 0 开始。
  • 元组可以使用解构赋值将元素赋值给变量。
  • 单个元素的元组需要使用逗号,否则会被解析为表达式。
  • 元组可以用于函数返回多个值。
  • 元组可以用于模式匹配,将元组中的元素赋值给变量。
  • ...

实用元组示例

#![allow(unused)]
fn main() {
fn practical_tuples() {
    // 函数返回多个值
    let result = divide_and_remainder(17, 5);
    let (quotient, remainder) = result;
    println!("17 除以 5 的商和余数: {}, {}", quotient, remainder);
    
    // 使用解构直接获取结果
    let (sum, product) = calculate_sum_product(10, 20);
    println!("和: {}, 积: {}", sum, product);
    
    // 存储混合类型的数据
    let person_info = ("张三", 25, 175.5, true);
    let (name, age, height, is_student) = person_info;
    println!("{}今年{}岁,身高{:.1}cm,状态:{}", name, age, height, 
             if is_student { "学生" } else { "非学生" });
    
    // 嵌套元组
    let nested_tuple = (1, (2, 3), 4);
    let inner_tuple = nested_tuple.1;
    let first_inner = inner_tuple.0;  // 2
    println!("嵌套元组中的值: {}", first_inner);
}

// 返回元组的函数示例
fn divide_and_remainder(dividend: i32, divisor: i32) -> (i32, i32) {
    let quotient = dividend / divisor;
    let remainder = dividend % divisor;
    (quotient, remainder)
}

fn calculate_sum_product(a: i32, b: i32) -> (i32, i32) {
    (a + b, a * b)
}
}

Result:

17 除以 5 的商和余数: 3, 2
和: 30, 积: 200
张三今年25岁,身高175.5cm,状态:学生
嵌套元组中的值: 2

元组在模式匹配中的应用

#![allow(unused)]
fn main() {
fn tuple_pattern_matching() {
    let coordinates = (10, 20);
    
    match coordinates {
        (0, 0) => println!("原点"),
        (x, 0) => println!("在X轴上,X坐标: {}", x),
        (0, y) => println!("在Y轴上,Y坐标: {}", y),
        (x, y) => println!("坐标点: ({}, {})", x, y),
    }
    
    // 包含条件守卫的模式
    let point = (15, 30);
    match point {
        (x, y) if x == y => println!("在对角线上: ({}, {})", x, y),
        (x, y) if x + y == 45 => println!("坐标和为45: ({}, {})", x, y),
        (x, y) => println!("一般坐标: ({}, {})", x, y),
    }
    
    // 解构函数参数
    let (name, age) = get_person_info();
    println!("个人信息: {},{}岁", name, age);
}

fn get_person_info() -> (&'static str, u32) {
    ("李四", 30)
}
}

Result:

坐标点: (10, 20)
坐标和为45: (15, 30)
个人信息: 李四,30岁

关键点:

  • 元组可以包含不同类型的元素。
  • 元组可以用于模式匹配,以提取和操作元组中的值。
  • 元组可以用于函数返回值,以返回多个值。
  • 元组可以用于解构赋值,以将元组中的值分配给多个变量。
  • 元组可以用于模式匹配中的条件守卫,以根据条件执行不同的代码块。
  • 元组可以用于函数参数,以传递多个值给函数。
  • 元组可以用于解构函数参数,以将函数参数中的值分配给多个变量。
  • 元组可以用于模式匹配中的条件守卫,以根据条件执行不同的代码块。
  • 元组可以用于函数返回值,以返回多个值给调用者。
  • ...

2.3.2 数组(Array)

数组是固定长度的相同类型元素的集合。数组长度在编译时确定,不能动态增长。

数组基础操作

#![allow(unused)]
fn main() {
fn array_basics() {
    // 数组声明和初始化
    let numbers: [i32; 5] = [1, 2, 3, 4, 5];
    let floats = [3.14, 2.71, 1.41, 1.73];  // 类型推导
    let chars = ['R', 'u', 's', 't'];       // 字符数组
    
    // 访问数组元素
    let first = numbers[0];
    let last = numbers[4];
    println!("第一个元素: {}, 最后一个元素: {}", first, last);
    
    // 数组长度
    println!("numbers数组长度: {}", numbers.len());
    
    // 初始化相同值的数组
    let repeated = [0; 10];  // 长度为10的数组,所有元素都是0
    println!("重复值数组长度: {}", repeated.len());
    
    // 遍历数组
    for (index, &value) in numbers.iter().enumerate() {
        println!("numbers[{}] = {}", index, value);
    }
}
}

Result:

第一个元素: 1, 最后一个元素: 5
numbers数组长度: 5
重复值数组长度: 10
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5

关键点:

  • 数组长度在编译时确定,不能动态增长。
  • 数组元素类型相同。
  • 数组元素可以通过索引访问。
  • 数组长度可以通过 len() 方法获取。
  • 数组可以初始化为相同值。
  • 数组可以遍历。
  • 数组元素可以通过 iter() 方法获取迭代器,然后使用 enumerate() 方法获取索引和值。
  • 数组元素可以通过 & 符号获取引用,以避免所有权转移。
  • 数组元素可以通过 iter_mut() 方法获取可变引用,以修改数组元素。
  • 数组元素可以通过 get() 方法获取可变引用,以修改数组元素。
  • 数组元素可以通过 get_mut() 方法获取可变引用,以修改数组元素。
  • ...

数组与循环

#![allow(unused)]
fn main() {
fn array_loops() {
    let arr = [10, 20, 30, 40, 50];
    let mut sum = 0;
    
    // 方法1: 使用索引循环
    let len = arr.len();
    for i in 0..len {
        sum += arr[i];
        println!("添加 arr[{}] = {}, 当前总和: {}", i, arr[i], sum);
    }
    println!("数组总和: {}", sum);
    
    // 方法2: 直接遍历元素(更安全)
    let mut sum2 = 0;
    for &value in &arr {
        sum2 += value;
        println!("元素值: {}", value);
    }
    println!("重新计算的总和: {}", sum2);
    
    // 方法3: enumerate遍历
    for (i, &value) in arr.iter().enumerate() {
        println!("索引 {}: 值 {}", i, value);
    }
}
}

Result:

添加 arr[0] = 10, 当前总和: 10
添加 arr[1] = 20, 当前总和: 30
添加 arr[2] = 30, 当前总和: 60
添加 arr[3] = 40, 当前总和: 100
添加 arr[4] = 50, 当前总和: 150
数组总和: 150
元素值: 10
元素值: 20
元素值: 30
元素值: 40
元素值: 50
重新计算的总和: 150
索引 0: 值 10
索引 1: 值 20
索引 2: 值 30
索引 3: 值 40
索引 4: 值 50

关键点:

  • 使用 & 符号获取不可变引用,以遍历数组元素。
  • 使用 iter() 方法获取不可变引用,以遍历数组元素。
  • 使用 iter_mut() 方法获取可变引用,以修改数组元素。
  • 使用 enumerate() 方法获取索引和值,以遍历数组元素。
  • ...

多维数组

#![allow(unused)]
fn main() {
fn multidimensional_arrays() {
    // 二维数组
    let matrix: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6],
    ];
    
    println!("矩阵内容:");
    for (i, row) in matrix.iter().enumerate() {
        for (j, &value) in row.iter().enumerate() {
            print!("matrix[{}][{}] = {}  ", i, j, value);
        }
        println!();
    }
    
    // 访问二维数组元素
    let element = matrix[1][2];  // 第二行第三列的值: 6
    println!("matrix[1][2] = {}", element);
    
    // 三维数组示例
    let three_d: [[[i32; 2]; 2]; 2] = [
        [[1, 2], [3, 4]],
        [[5, 6], [7, 8]],
    ];
    
    println!("三维数组内容:");
    for (i, depth) in three_d.iter().enumerate() {
        for (j, row) in depth.iter().enumerate() {
            for (k, &value) in row.iter().enumerate() {
                print!("[{}][{}][{}] = {}  ", i, j, k, value);
            }
            println!();
        }
    }
}
}

Result:

矩阵内容:
matrix[0][0] = 1  matrix[0][1] = 2  matrix[0][2] = 3
matrix[1][0] = 4  matrix[1][1] = 5  matrix[1][2] = 6
matrix[1][2] = 6
三维数组内容:
[0][0][0] = 1  [0][0][1] = 2
[0][1][0] = 3  [0][1][1] = 4
[1][0][0] = 5  [1][0][1] = 6
[1][1][0] = 7  [1][1][1] = 8

关键点:

  • 使用get方法安全地访问数组元素,避免越界错误。
  • 使用iter方法遍历数组,并使用enumerate方法获取索引。
  • 使用match表达式检查get方法返回的Option类型,以处理可能越界的情况。
  • 使用多维数组时,可以嵌套使用iterenumerate方法来遍历每个维度。
  • 使用print!println!宏来格式化输出。
  • ...

数组越界检查

#![allow(unused)]
fn main() {
fn array_bounds_checking() {
    let arr = [10, 20, 30];
    
    // 安全的访问
    if let Some(&value) = arr.get(1) {
        println!("arr[1] = {}", value);
    }
    
    // 检查是否越界
    match arr.get(5) {
        Some(value) => println!("arr[5] = {}", value),
        None => println!("数组越界! 最大索引: {}", arr.len() - 1),
    }
    
    // 数组切片(引用数组的一部分)
    let slice = &arr[0..2];  // 包含索引0到1
    println!("切片内容: {:?}", slice);
    
    let slice_to_end = &arr[1..];  // 从索引1到末尾
    println!("从索引1开始的切片: {:?}", slice_to_end);
    
    let slice_from_start = &arr[..2];  // 从开头到索引2(不包含2)
    println!("从开头到索引2的切片: {:?}", slice_from_start);
    
    let full_slice = &arr[..];  // 整个数组的切片
    println!("完整切片: {:?}", full_slice);
}
}

Result:

arr[1] = 20
数组越界! 最大索引: 2
切片内容: [10, 20]
从索引1开始的切片: [20, 30]
从开头到索引2的切片: [10, 20]
完整切片: [10, 20, 30]

关键点:

  • 使用get方法安全地访问数组元素,避免越界错误。
  • 使用match表达式检查get方法返回的Option类型,以处理可能越界的情况。
  • 使用数组切片(引用数组的一部分)来访问数组的一部分,避免越界错误。
  • ...

实用数组操作

#![allow(unused)]
fn main() {
fn array_operations() {
    let mut numbers = [64, 34, 25, 12, 22, 11, 90];
    
    println!("原始数组: {:?}", numbers);
    
    // 查找最大值和最小值
    let max = numbers.iter().max().unwrap();
    let min = numbers.iter().min().unwrap();
    println!("最大值: {}, 最小值: {}", max, min);
    
    // 计算数组总和和平均值
    let sum: i32 = numbers.iter().sum();
    let average = sum as f64 / numbers.len() as f64;
    println!("总和: {}, 平均值: {:.2}", sum, average);
    
    // 过滤和变换
    let even_numbers: Vec<_> = numbers.iter()
        .filter(|&&x| x % 2 == 0)
        .copied()
        .collect();
    println!("偶数: {:?}", even_numbers);
    
    let squared: Vec<_> = numbers.iter()
        .map(|&x| x * x)
        .collect();
    println!("平方: {:?}", squared);
    
    // 检查是否包含某个值
    let contains_25 = numbers.contains(&25);
    let position = numbers.iter().position(|&x| x == 25);
    println!("包含25: {}, 位置: {:?}", contains_25, position);
    
    // 排序
    let mut sorted = numbers;
    sorted.sort();
    println!("排序后: {:?}", sorted);
}
}

Result:

原始数组: [64, 34, 25, 12, 22, 11, 90]
最大值: 90, 最小值: 11
总和: 258, 平均值: 36.86
偶数: [64, 34, 12, 22, 90]
平方: [4096, 1156, 625, 144, 484, 121, 8100]
包含25: true, 位置: Some(2)
排序后: [11, 12, 22, 25, 34, 64, 90]

关键点:

  • iter() 方法返回一个迭代器,用于遍历数组元素。
  • sum() 方法计算数组元素的总和。
  • copied() 方法将迭代器中的元素复制到新向量中。
  • filter() 方法用于过滤数组元素。
  • map() 方法用于变换数组元素。
  • contains() 方法用于检查数组是否包含某个值。
  • position() 方法用于查找数组中某个值的索引。
  • sort() 方法用于对数组进行排序。
  • enumerate() 方法用于同时获取数组元素的索引和值。
  • ...

字符串数组和字符处理

#![allow(unused)]
fn main() {
fn string_and_char_arrays() {
    // 字符串数组
    let fruits = ["苹果", "香蕉", "橙子", "葡萄"];
    
    for (i, fruit) in fruits.iter().enumerate() {
        println!("fruits[{}] = {}", i, fruit);
    }
    
    // 字符数组
    let word = ['R', 'u', 's', 't'];
    let word_str: String = word.iter().collect();
    println!("字符数组转换为字符串: {}", word_str);
    
    // 字符数组的遍历
    for char in &word {
        println!("字符: {}", char);
        // 转换为ASCII码
        println!("ASCII码: {}", *char as u8);
    }
    
    // 计算字符串的长度(以字符计)
    let multi_char_str = "你好,世界! 🌍";
    let chars: Vec<char> = multi_char_str.chars().collect();
    println!("字符串: {}", multi_char_str);
    println!("字符数量: {}", chars.len());
    println!("字节长度: {}", multi_char_str.len());
}
}

Result:

fruits[0] = 苹果
fruits[1] = 香蕉
fruits[2] = 橙子
fruits[3] = 葡萄
字符数组转换为字符串: Rust
字符: R
ASCII码: 82
字符: u
ASCII码: 117
字符: s
ASCII码: 115
字符: t
ASCII码: 116
字符串: 你好,世界! 🌍
字符数量: 8
字节长度: 23

关键点:

  • iter() 方法用于获取数组的迭代器。
  • enumerate() 方法用于同时获取数组元素的索引和值。
  • collect() 方法用于将迭代器转换为集合类型。
  • chars() 方法用于将字符串转换为字符迭代器。
  • len() 方法用于获取字符串的长度(以字符计)。
  • ...

字符串切片

#![allow(unused)]

fn main() {
### 数组在函数中的应用

```rust
fn array_in_functions() {
    let arr = [1, 2, 3, 4, 5];
    
    // 传递数组引用
    let sum = sum_array(&arr);
    let max = max_array(&arr);
    
    println!("数组: {:?}", arr);
    println!("总和: {}, 最大值: {}", sum, max);
    
    // 修改数组(需要mut)
    let mut mut_arr = [10, 20, 30];
    modify_array(&mut mut_arr);
    println!("修改后: {:?}", mut_arr);
    
    // 返回数组
    let squared = square_array(&arr);
    println!("平方后: {:?}", squared);
}

// 计算数组总和
fn sum_array(arr: &[i32]) -> i32 {
    arr.iter().sum()
}

// 找最大值
fn max_array(arr: &[i32]) -> i32 {
    arr.iter().max().copied().unwrap_or(0)
}

// 修改数组元素
fn modify_array(arr: &mut [i32]) {
    for i in 0..arr.len() {
        arr[i] *= 2;
    }
}

// 返回平方数组
fn square_array(arr: &[i32]) -> Vec<i32> {
    arr.iter().map(|&x| x * x).collect()
}
}

Result:

数组: [1, 2, 3, 4, 5]
总和: 15, 最大值: 5
修改后: [20, 40, 60]
平方后: [1, 4, 9, 16, 25]

关键点:

  • &arr 传递数组引用,避免所有权转移。
  • &mut mut_arr 传递可变数组引用,允许修改数组。
  • &arr 返回数组引用,避免所有权转移。
  • &arr 作为参数传递时,不需要显式地使用 &,因为数组引用已经是引用类型。
  • &arr 返回数组引用时,不需要显式地使用 &,因为数组引用已经是引用类型。
  • &mut mut_arr 作为参数传递时,需要显式地使用 &mut,因为数组引用是可变引用类型。
  • &mut mut_arr 返回数组引用时,需要显式地使用 &mut,因为数组引用是可变引用类型。
  • &arr&mut mut_arr 在函数内部都是引用类型,不需要显式地使用 &&mut
  • ...

2.4 字符串类型

2.4.1 字符串字面量和切片

Rust 中的字符串字面量是不可变的、硬编码的文本,使用双引号定义,如 "hello"。它们是 &str 类型(字符串切片),指向静态内存中的 UTF-8 编码字节序列。切片(slice)是引用现有数据的视图,如 &[T],字符串切片 &str 是对字符串的不可变引用。

#![allow(unused)]
fn main() {
fn string_slices() {
    // 字符串字面量(&str)- 编译时常量
    let greeting = "Hello, Rust!";
    let name = "World";
    
    // 切片(不拥有所有权)
    let slice = &greeting[0..5];           // "Hello"
    let slice_from_middle = &greeting[7..11]; // "Rust"
    
    println!("完整问候: {}", greeting);
    println!("切片: {}", slice);
    
    // 字符串方法
    let trimmed = "  hello  ".trim();      // "hello"
    let uppercase = "rust".to_uppercase(); // "RUST"
    let lowercase = "RUST".to_lowercase(); // "rust"
    
    // 查找和分割
    let text = "one,two,three,four";
    let parts: Vec<&str> = text.split(',').collect();
    println!("分割结果: {:?}", parts);
    
    // 替换
    let replaced = "hello world".replace("world", "Rust");
    println!("替换后: {}", replaced);
}
}

Result:

完整问候: Hello, Rust!
切片: Hello
分割结果: ["one", "two", "three", "four"]
替换后: hello Rust

关键点:

  • 字面量生命周期为 'static,不可变,它们是 &str 类型。
  • 切片不拥有数据,仅借用;索引必须是有效 UTF-8 边界,否则 panic。
  • 常用作函数参数,促进零拷贝。
  • 字符串切片是引用类型,可以引用字符串字面量或 String 类型。
  • 字符串切片可以用于字符串操作,如查找、替换和分割等。
  • 字符串切片不拥有所有权,因此它们的生命周期不能超过它们引用的数据的生命周期。
  • 字符串切片可以用于字符串字面量和 String 类型,但不能用于 char 类型。
  • 字符串切片可以通过 &str 类型转换为 String 类型,但需要使用 to_string 方法。
  • 字符串切片可以通过 split 方法分割为多个子字符串,并返回一个 Vec<&str> 类型的结果。
  • ...

2.4.2 String 类型

String 是可增长、可变、拥有的 UTF-8 编码字符串,存储在堆上。不同于 &str,String 拥有数据,可以修改(如追加)。它实现了 Deref 到 &str,允许隐式转换为切片。

#![allow(unused)]
fn main() {
fn string_type() {
    // String 类型(拥有所有权)
    let mut s = String::new();             // 空字符串
    let s1 = String::from("hello");        // 从字符串字面量创建
    let s2 = "world".to_string();          // 转换为 String
    
    // 追加内容
    s.push('A');                           // 追加字符
    s.push_str("pple");                    // 追加字符串
    s += " Banana";                        // 连接操作符
    
    println!("字符串 s: {}", s);
    
    // 格式化
    let name = "Alice";
    let age = 30;
    let formatted = format!("{} is {} years old", name, age);
    println!("格式化: {}", formatted);
    
    // 使用宏
    println!("测试值: {}, 另一个值: {}", 42, "text");
    
    // 所有权示例
    let original = String::from("original");
    let moved = original;                  // 所有权转移
    // println!("{}", original);           // 编译错误!original 已移动
    println!("移动后的字符串: {}", moved);
}
}

Result:

字符串 s: Apple Banana
格式化: Alice is 30 years old
测试值: 42, 另一个值: text
移动后的字符串: original

关键点:

  • String 类型是拥有所有权的,因此需要使用 String::fromto_string 方法来创建 String 实例。
  • pushpush_str 方法用于向 String 实例中追加内容。
  • 所有权规则适用:移动后不可用,除非克隆(.clone())。
  • format! 宏用于格式化字符串。
  • println! 宏用于打印字符串。
  • String 的所有权转移示例展示了所有权转移的概念,即 original 在赋值给 moved 后,original 不再有效。
  • ...

2.5 控制流

2.5.1 if 条件语句

Rust 的 if 是表达式,可返回值的条件分支。无需括号包围条件,支持 elseelse if。条件必须是 bool 类型,无隐式转换。

#![allow(unused)]
fn main() {
fn conditional_statements() {
    let number = 7;
    
    // 基本 if-else
    if number < 5 {
        println!("数字小于 5");
    } else if number == 5 {
        println!("数字等于 5");
    } else {
        println!("数字大于 5");
    }
    
    // if 作为表达式(返回值)
    let grade = if number >= 90 {
        "A"
    } else if number >= 80 {
        "B"
    } else if number >= 70 {
        "C"
    } else {
        "F"
    };
    
    println!("成绩: {}", grade);
    
    // 条件赋值
    let status = if number % 2 == 0 {
        "偶数"
    } else {
        "奇数"
    };
    println!("{} 是 {}", number, status);
}
}

Result:

数字大于 5
成绩: F
7 是 奇数

关键点:

  • if 语句的基本用法,包括条件判断和分支执行。
  • if 语句可以作为表达式返回值。
  • if 语句的嵌套使用。
  • 条件赋值的使用,根据条件为变量赋值。
  • if 语句的执行顺序,根据条件判断结果选择执行相应的分支。
  • if 语句的返回值,可以是任意类型,但需要与上下文中的变量类型匹配。
  • ...

2.5.2 循环控制

loop 无穷循环

#![allow(unused)]

fn main() {
## 2.5.2 循环控制

### loop 无穷循环

`loop` 是无限循环,直到显式 `break`。可返回值的表达式,支持标签用于嵌套循环控制。

```rust
fn loop_examples() {
    // 基本 loop
    let mut counter = 0;
    loop {
        counter += 1;
        println!("计数器: {}", counter);
        
        if counter >= 5 {
            break;                          // 退出循环
        }
    }
    
    // loop 作为表达式(返回值)
    let result = loop {
        counter += 1;
        
        if counter == 10 {
            break counter;                 // 退出并返回值
        }
    };
    
    println!("循环结果: {}", result);
}
}

Result:

计数器: 1
计数器: 2
计数器: 3
计数器: 4
计数器: 5
循环结果: 10

关键点:

  • break 退出循环
  • break 可以返回值
  • continue 跳过本次循环
  • loop 可以作为表达式,返回值
  • loop 可以嵌套
  • loop 可以与标签(label)配合使用,用于退出多层嵌套循环,标签如 'outer: loop {} 用于多层控制。
  • ...

while 条件循环

while 是条件循环,在条件为 true 时执行。条件必须是 bool。

#![allow(unused)]
fn main() {
fn while_examples() {
    let mut number = 3;
    
    while number != 0 {
        println!("倒计时: {}", number);
        number -= 1;
    }
    
    println!("发射!");
    
    // 数组遍历
    let array = [10, 20, 30, 40, 50];
    let mut index = 0;
    
    while index < array.len() {
        println!("索引 {}: 值 {}", index, array[index]);
        index += 1;
    }
}
}

Result:

倒计时: 3
倒计时: 2
倒计时: 1
发射!
索引 0: 值 10
索引 1: 值 20
索引 2: 值 30
索引 3: 值 40
索引 4: 值 50

Result:

  • 无 do-while,但可用 loop 模拟。
  • 适合未知迭代次数但有条件的情况。
  • while 循环可以遍历数组,循环也可以嵌套
  • while 循环可以与标签(label)配合使用,用于退出多层嵌套循环
  • while 循环可以与 breakcontinue 配合使用,用于控制循环的执行
  • while 循环可以与 loop 配合使用,用于创建无限循环
  • while 循环可以与 for 循环配合使用,用于遍历集合
  • while 循环可以与 match 配合使用,用于处理多种情况
  • while 循环可以与 if 配合使用,用于条件判断
  • while 循环可以与 let 配合使用,用于声明变量
  • while 循环可以与 return 配合使用,用于返回值
  • while 循环可以与 yield 配合使用,用于生成器函数
  • while 循环可以与 try 配合使用,用于处理错误
  • while 循环可以与 await 配合使用,用于异步编程
  • while 循环可以与 panic! 配合使用,用于处理异常
  • while 循环可以与 println! 配合使用,用于输出日志
  • while 循环可以与 debug!info!等配合使用,用于调试
  • while 循环可以与 assert! 配合使用,用于断言
  • while 循环可以与 unwrap!expect! 配合使用,用于处理 OptionResult等等
  • ...

for 循环和迭代器

for 用于迭代集合,如范围或迭代器。语法 for item in iterator {},高效处理所有权。

#![allow(unused)]
fn main() {
fn for_loop_examples() {
    // 基本 for 循环
    for i in 0..5 {                        // 0 到 4
        println!("for 循环: {}", i);
    }
    
    // 包含结束值的 range
    for i in 0..=5 {                       // 0 到 5
        println!("包含结束值: {}", i);
    }
    
    // 数组迭代
    let array = [1, 2, 3, 4, 5];
    for item in array {
        println!("数组项: {}", item);
    }
    
    // 索引和值的迭代
    let names = vec!["Alice", "Bob", "Charlie"];
    for (index, name) in names.iter().enumerate() {
        println!("{}: {}", index, name);
    }
    
    // 字符串字符迭代
    let text = "Rust";
    for char in text.chars() {
        println!("字符: {}", char);
    }
    
    // 字节迭代
    for byte in text.bytes() {
        println!("字节: {}", byte);
    }
}
}

Result:

for 循环: 0
for 循环: 1
for 循环: 2
for 循环: 3
for 循环: 4
包含结束值: 0
包含结束值: 1
包含结束值: 2
包含结束值: 3
包含结束值: 4
包含结束值: 5
数组项: 1
数组项: 2
数组项: 3
数组项: 4
数组项: 5
0: Alice
1: Bob
2: Charlie
字符: R
字符: u
字符: s
字符: t
字节: 82
字节: 117
字节: 115
字节: 116

关键点:

  • for 循环用于遍历范围、数组、向量、字符串等。
  • 0..5 创建一个从 0 到 4 的范围。
  • 0..=5 创建一个从 0 到 5 的范围(包含 5)。
  • array 是一个数组,names 是一个向量。
  • enumerate 方法用于获取索引和值。
  • ...

2.5.3 模式匹配

模式匹配通过 match 表达式解构值,处理多种情况。必须穷尽所有可能(或用 _ 通配)。支持绑定、守卫和嵌套。

#![allow(unused)]
fn main() {
fn pattern_matching() {
    let x = 42;
    
    match x {
        0 => println!("零"),
        1..=10 => println!("一到十之间"),
        20 | 30 | 40 => println!("20, 30 或 40"),
        n if n % 2 == 0 => println!("偶数: {}", n),
        _ => println!("其他值: {}", x),    // 通配符
    }
    
    // 绑定值的模式
    match x {
        0 => println!("零"),
        1 => println!("一"),
        n => println!("其他: {}", n),      // 绑定值
    }
    
    // 复合模式
    let point = (0, 7);
    match point {
        (0, 0) => println!("原点"),
        (0, y) => println!("在 Y 轴上: y = {}", y),
        (x, 0) => println!("在 X 轴上: x = {}", x),
        (x, y) => println!("点 ({}, {})", x, y),
    }
}
}

Result:

偶数: 42
其他: 42
在 Y 轴上: y = 7

关键点:

  • 模式如绑定(x @ 1..=5)、解构(元组、结构体)。
  • 与 if let、while let 结合简化可选匹配。
  • match 语句用于模式匹配。
  • if 表达式可以在 match 分支中使用。
  • _ 是通配符,匹配任何值。
  • 绑定值可以在 match 分支中使用。
  • 复合模式可以匹配多个值。
  • match 语句必须覆盖所有可能的值。
  • match 语句可以返回值。
  • match 语句用途广泛,可用于错误处理、枚举类型、元组、结构体、引用(可变/不可变)、切片、数组、字符串、闭包、函数、宏、模式匹配、类型转换、类型检查等场景。
  • ...

2.6 函数定义与调用

2.6.1 函数基础

Rust 中的函数是代码的可重用块,通过 fn 关键字定义。函数名使用蛇形命名法(snake_case),并可接受参数和返回值。每个程序至少有一个 main 函数作为入口。函数体用 {}包围,支持表达式和语句。Rust 函数是静态类型的,确保类型安全。

#![allow(unused)]
fn main() {
// 函数定义
fn greet(name: &str) {
    println!("你好, {}!", name);
}

// 有返回值的函数
fn add(a: i32, b: i32) -> i32 {
    a + b                                 // 没有分号表示返回值
}

// 显式返回语句
fn multiply(x: i32, y: i32) -> i32 {
    return x * y;                         // 显式返回
}

// 函数调用
fn function_examples() {
    greet("Rust");
    let sum = add(5, 3);
    let product = multiply(4, 7);
    
    println!("5 + 3 = {}", sum);
    println!("4 × 7 = {}", product);
    
    // 函数作为表达式
    let result = {
        let a = 10;
        let b = 20;
        a + b                             // 块表达式返回值
    };
    println!("块表达式结果: {}", result);
}
}

Result:

你好, Rust!
5 + 3 = 8
4 × 7 = 28
块表达式结果: 30

关键点:

  • 函数定义使用 fn 关键字。
  • 函数参数类型在参数名后面指定。
  • 函数返回值类型在 -> 后面指定。
  • 函数体中的最后一行表达式是返回值,不需要分号。
  • 函数调用使用函数名和参数列表。
  • 函数可以返回值,也可以不返回值。
  • 函数可以包含块表达式,块表达式的最后一行是返回值。
  • 函数可以嵌套定义,但不能嵌套调用。
  • 函数可以递归调用,但不能递归定义。
  • 函数可以接受可变参数,但不能接受可变参数数量。
  • ...

2.6.2 函数参数和返回值

函数参数在括号中定义,指定类型。Rust 使用所有权系统:参数可通过值传递(移动所有权)或引用(借用)。可变参数需用 mut。参数是不可变的,除非显式标记。 函数通过 -> Type 指定返回值类型。最后表达式隐式返回,或用 return 显式返回。无返回值默认为 ()(单元类型)。多值返回用元组。

#![allow(unused)]
fn main() {
// 多个参数
fn calculate_area(length: f64, width: f64) -> f64 {
    length * width
}

// 可变参数数量
fn print_values(values: &[i32]) {
    for value in values {
        println!("值: {}", value);
    }
}

// 元组返回
fn get_coordinates() -> (i32, i32) {
    (10, 20)
}

// 命名返回结构
#[derive(Debug)]
struct Rectangle {
    width: f64,
    height: f64,
}

fn create_rectangle(width: f64, height: f64) -> Rectangle {
    Rectangle { width, height }
}

fn calculate_rectangle_area(rect: &Rectangle) -> f64 {
    rect.width * rect.height
}

fn function_parameters() {
    let area = calculate_area(5.0, 3.0);
    println!("矩形面积: {}", area);
    
    let values = vec![1, 2, 3, 4, 5];
    print_values(&values);
    
    let (x, y) = get_coordinates();
    println!("坐标: ({}, {})", x, y);
    
    let rectangle = create_rectangle(4.0, 6.0);
    let rect_area = calculate_rectangle_area(&rectangle);
    println!("矩形面积: {}", rect_area);
}
}

Result:

矩形面积: 15
值: 1
值: 2
值: 3
值: 4
值: 5
坐标: (10, 20)
矩形面积: 24

关键点:

  • Rust 中的函数参数和返回值类型必须显式声明。
  • Rust 中的函数参数和返回值类型可以是泛型、元组、结构体、枚举、闭包等多种类型。
  • ...

2.6.3 高阶函数示例

#![allow(unused)]
fn main() {
// 基础函数
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

// 函数作为参数
fn apply_function<F>(value: i32, f: F) -> i32
where
    F: Fn(i32) -> i32,
{
    f(value)
}

// 函数作为返回值
fn get_operation(operation: &str) -> fn(i32, i32) -> i32 {
    match operation {
        "add" => add,
        "multiply" => multiply,
        _ => add, // 默认操作
    }
}

fn higher_order_functions() {
    let result1 = apply_function(5, |x| x * x); // 闭包
    let result2 = apply_function(10, |x| x + 100); // 另一个闭包

    println!("平方: {}", result1);
    println!("加100: {}", result2);

    let operation = get_operation("add");
    let result3 = operation(15, 25);
    println!("函数指针结果: {}", result3);
}
}

Result:

平方: 25
加100: 110
函数指针结果: 40

关键点:

  • Rust 中的函数可以作为参数传递。
  • Rust 中的函数可以作为返回值。
  • Rust 中的闭包是一种匿名函数,可以作为参数传递或作为返回值。
  • Rust 中的函数指针是一种指向函数的指针,可以作为参数传递或作为返回值。
  • Rust 中的泛型函数可以接受不同类型的参数,并返回不同类型的值。
  • Rust 中的函数可以接受元组、结构体、枚举等多种类型的参数,并返回不同类型的值。
  • Rust 中的函数可以接受可变参数,并返回不同类型的值。
  • ...

2.7 实践项目:科学计算器与数据处理工具

2.7.1 项目需求分析

创建一个功能完善的科学计算器,支持:

  • 基础和科学运算
  • 表达式解析和求值
  • 数据统计分析
  • 历史记录功能

2.7.2 项目结构设计

// src/main.rs
mod calculator;
mod data;
mod history;
mod utils;

use calculator::{Calculator, Operation};
use data::Statistics;
use history::HistoryManager;
use utils::Error;

fn main() -> Result<(), Error> {
    println!("=== 科学计算器 v1.0 ===");
    
    let mut calculator = Calculator::new();
    let mut history = HistoryManager::new();
    
    // 示例计算
    run_example_calculations(&mut calculator, &mut history)?;
    
    Ok(())
}

fn run_example_calculations(
    calc: &mut Calculator, 
    history: &mut HistoryManager
) -> Result<(), Error> {
    // 基础运算
    let result1 = calc.add(10.0, 5.0)?;
    println!("10 + 5 = {}", result1);
    history.add_record("10 + 5", result1);
    
    let result2 = calc.multiply(result1, 2.0)?;
    println!("({}) × 2 = {}", result1, result2);
    history.add_record("10 + 5 * 2", result2);
    
    // 科学运算
    let result3 = calc.sqrt(16.0)?;
    println!("√16 = {}", result3);
    history.add_record("√16", result3);
    
    let result4 = calc.sin(30.0_f64.to_radians())?;
    println!("sin(30°) = {}", result4);
    history.add_record("sin(30°)", result4);
    
    // 表达式求值
    let expr_result = calc.evaluate_expression("(10 + 5) * 2 - √16")?;
    println!("(10 + 5) * 2 - √16 = {}", expr_result);
    history.add_record("(10 + 5) * 2 - √16", expr_result);
    
    // 统计计算
    let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
    let stats = calc.calculate_statistics(&data)?;
    println!("数据集统计: {:?}", stats);
    
    history.display();
    
    Ok(())
}

2.7.3 计算器核心模块

#![allow(unused)]
fn main() {
// src/calculator/mod.rs
pub mod operations;
pub mod parser;
pub mod evaluator;

use operations::Operation;
use parser::ExpressionParser;
use evaluator::ExpressionEvaluator;
use utils::Error;

pub struct Calculator {
    parser: ExpressionParser,
    evaluator: ExpressionEvaluator,
}

impl Calculator {
    pub fn new() -> Self {
        Self {
            parser: ExpressionParser::new(),
            evaluator: ExpressionEvaluator::new(),
        }
    }
    
    // 基础运算方法
    pub fn add(&self, a: f64, b: f64) -> Result<f64, Error> {
        Ok(a + b)
    }
    
    pub fn subtract(&self, a: f64, b: f64) -> Result<f64, Error> {
        Ok(a - b)
    }
    
    pub fn multiply(&self, a: f64, b: f64) -> Result<f64, Error> {
        Ok(a * b)
    }
    
    pub fn divide(&self, a: f64, b: f64) -> Result<f64, Error> {
        if b == 0.0 {
            return Err(Error::DivisionByZero);
        }
        Ok(a / b)
    }
    
    pub fn power(&self, base: f64, exponent: f64) -> Result<f64, Error> {
        Ok(base.powf(exponent))
    }
    
    pub fn sqrt(&self, value: f64) -> Result<f64, Error> {
        if value < 0.0 {
            return Err(Error::NegativeSquareRoot);
        }
        Ok(value.sqrt())
    }
    
    pub fn sin(&self, angle: f64) -> Result<f64, Error> {
        Ok(angle.sin())
    }
    
    pub fn cos(&self, angle: f64) -> Result<f64, Error> {
        Ok(angle.cos())
    }
    
    pub fn tan(&self, angle: f64) -> Result<f64, Error> {
        Ok(angle.tan())
    }
    
    pub fn ln(&self, value: f64) -> Result<f64, Error> {
        if value <= 0.0 {
            return Err(Error::InvalidLogarithm);
        }
        Ok(value.ln())
    }
    
    pub fn log(&self, value: f64, base: f64) -> Result<f64, Error> {
        if value <= 0.0 || base <= 0.0 || base == 1.0 {
            return Err(Error::InvalidLogarithm);
        }
        Ok(value.log(base))
    }
    
    pub fn factorial(&self, n: u64) -> Result<f64, Error> {
        if n > 20 {
            return Err(Error::FactorialTooLarge);
        }
        Ok((1..=n).product::<u64>() as f64)
    }
    
    // 表达式求值
    pub fn evaluate_expression(&self, expression: &str) -> Result<f64, Error> {
        let tokens = self.parser.tokenize(expression)?;
        let ast = self.parser.parse(tokens)?;
        self.evaluator.evaluate(&ast)
    }
    
    // 统计计算
    pub fn calculate_statistics(&self, data: &[f64]) -> Result<Statistics, Error> {
        if data.is_empty() {
            return Err(Error::EmptyDataSet);
        }
        
        let n = data.len() as f64;
        let sum: f64 = data.iter().sum();
        let mean = sum / n;
        
        // 计算方差
        let variance: f64 = data.iter()
            .map(|&x| (x - mean).powi(2))
            .sum::<f64>() / n;
        let std_dev = variance.sqrt();
        
        // 计算中位数
        let mut sorted_data = data.to_vec();
        sorted_data.sort_by(|a, b| a.partial_cmp(b).unwrap());
        let median = if n % 2.0 == 0.0 {
            (sorted_data[(n as usize / 2) - 1] + sorted_data[n as usize / 2]) / 2.0
        } else {
            sorted_data[n as usize / 2]
        };
        
        let min = data.iter().cloned().fold(f64::INFINITY, f64::min);
        let max = data.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
        
        // 计算众数
        let mut frequency = std::collections::HashMap::new();
        for &value in data {
            *frequency.entry(value).or_insert(0) += 1;
        }
        let max_count = frequency.values().max().unwrap_or(&0).clone();
        let mode: Vec<f64> = frequency
            .into_iter()
            .filter(|&(_, count)| count == max_count)
            .map(|(value, _)| value)
            .collect();
        
        Ok(Statistics {
            count: data.len(),
            mean,
            median,
            mode,
            variance,
            std_dev,
            min,
            max,
            sum,
        })
    }
}
}

2.7.4 表达式解析器

#![allow(unused)]
fn main() {
// src/calculator/parser.rs
use crate::utils::Error;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
    Number(f64),
    Identifier(String),
    Operator(Operator),
    LParen,
    RParen,
    Comma,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Operator {
    Add,
    Subtract,
    Multiply,
    Divide,
    Power,
    Sqrt,
    Sin,
    Cos,
    Tan,
    Ln,
    Log,
    Factorial,
}

#[derive(Debug, Clone)]
pub enum AstNode {
    Number(f64),
    Identifier(String),
    UnaryOp(Operator, Box<AstNode>),
    BinaryOp(Operator, Box<AstNode>, Box<AstNode>),
    FunctionCall(String, Vec<AstNode>),
}

pub struct ExpressionParser {
    // 操作符优先级
    precedence: std::collections::HashMap<Operator, i32>,
}

impl ExpressionParser {
    pub fn new() -> Self {
        let mut precedence = std::collections::HashMap::new();
        precedence.insert(Operator::Add, 1);
        precedence.insert(Operator::Subtract, 1);
        precedence.insert(Operator::Multiply, 2);
        precedence.insert(Operator::Divide, 2);
        precedence.insert(Operator::Power, 3);
        precedence.insert(Operator::Sqrt, 4);
        precedence.insert(Operator::Factorial, 5);
        precedence.insert(Operator::Sin, 6);
        precedence.insert(Operator::Cos, 6);
        precedence.insert(Operator::Tan, 6);
        precedence.insert(Operator::Ln, 6);
        precedence.insert(Operator::Log, 6);
        
        Self { precedence }
    }
    
    pub fn tokenize(&self, input: &str) -> Result<Vec<Token>, Error> {
        let mut tokens = Vec::new();
        let mut chars = input.chars().peekable();
        
        while let Some(ch) = chars.next() {
            match ch {
                '0'..='9' | '.' => {
                    let mut number_str = ch.to_string();
                    
                    // 继续读取数字和小数点
                    while let Some(&next_ch) = chars.peek() {
                        if next_ch.is_numeric() || next_ch == &'.' {
                            number_str.push(chars.next().unwrap());
                        } else {
                            break;
                        }
                    }
                    
                    let number: f64 = number_str.parse()
                        .map_err(|_| Error::InvalidNumber(number_str))?;
                    tokens.push(Token::Number(number));
                }
                'a'..='z' | 'A'..='Z' | '_' => {
                    let mut ident = ch.to_string();
                    
                    // 继续读取标识符字符
                    while let Some(&next_ch) = chars.peek() {
                        if next_ch.is_alphanumeric() || next_ch == &'_' {
                            ident.push(chars.next().unwrap());
                        } else {
                            break;
                        }
                    }
                    
                    tokens.push(Token::Identifier(ident));
                }
                '+' => tokens.push(Token::Operator(Operator::Add)),
                '-' => tokens.push(Token::Operator(Operator::Subtract)),
                '*' => tokens.push(Token::Operator(Operator::Multiply)),
                '/' => tokens.push(Token::Operator(Operator::Divide)),
                '^' => tokens.push(Token::Operator(Operator::Power)),
                '(' => tokens.push(Token::LParen),
                ')' => tokens.push(Token::RParen),
                ',' => tokens.push(Token::Comma),
                ' ' | '\t' | '\n' | '\r' => continue, // 跳过空白字符
                _ => return Err(Error::InvalidCharacter(ch)),
            }
        }
        
        Ok(tokens)
    }
    
    pub fn parse(&self, tokens: Vec<Token>) -> Result<AstNode, Error> {
        let mut output = Vec::new();
        let mut operators = Vec::new();
        
        for token in tokens {
            match token {
                Token::Number(n) => output.push(AstNode::Number(n)),
                Token::Identifier(ident) => output.push(AstNode::Identifier(ident)),
                Token::Operator(op) => {
                    while let Some(Token::Operator(prev_op)) = operators.last() {
                        if self.get_precedence(prev_op) >= self.get_precedence(&op) {
                            self.pop_operator_to_output(&mut operators, &mut output)?;
                        } else {
                            break;
                        }
                    }
                    operators.push(Token::Operator(op));
                }
                Token::LParen => operators.push(token),
                Token::RParen => {
                    while let Some(op) = operators.pop() {
                        match op {
                            Token::LParen => break,
                            Token::Operator(op) => self.pop_operator_to_output(&operators, &mut output)?,
                            _ => return Err(Error::MismatchedParen),
                        }
                    }
                }
                Token::Comma => {
                    while let Some(token) = operators.pop() {
                        match token {
                            Token::LParen => return Err(Error::MismatchedParen),
                            Token::Operator(op) => self.pop_operator_to_output(&operators, &mut output)?,
                            _ => {}
                        }
                    }
                }
            }
        }
        
        while let Some(token) = operators.pop() {
            match token {
                Token::Operator(op) => self.pop_operator_to_output(&operators, &mut output)?,
                Token::LParen | Token::RParen | Token::Comma => 
                    return Err(Error::MismatchedParen),
            }
        }
        
        if output.len() != 1 {
            return Err(Error::InvalidExpression);
        }
        
        Ok(output.remove(0))
    }
    
    fn get_precedence(&self, op: &Operator) -> i32 {
        *self.precedence.get(op).unwrap_or(&0)
    }
    
    fn pop_operator_to_output(
        &self, 
        operators: &mut Vec<Token>, 
        output: &mut Vec<AstNode>
    ) -> Result<(), Error> {
        if let Some(Token::Operator(op)) = operators.pop() {
            match op {
                Operator::Sqrt | Operator::Sin | Operator::Cos | Operator::Tan 
                | Operator::Ln | Operator::Factorial => {
                    if let Some(operand) = output.pop() {
                        output.push(AstNode::UnaryOp(op, Box::new(operand)));
                    } else {
                        return Err(Error::InsufficientOperands);
                    }
                }
                _ => {
                    if let (Some(right), Some(left)) = (output.pop(), output.pop()) {
                        output.push(AstNode::BinaryOp(op, Box::new(left), Box::new(right)));
                    } else {
                        return Err(Error::InsufficientOperands);
                    }
                }
            }
        }
        Ok(())
    }
}
}

2.7.5 表达式求值器

#![allow(unused)]
fn main() {
// src/calculator/evaluator.rs
use super::parser::{AstNode, Operator};
use crate::utils::Error;

pub struct ExpressionEvaluator {
    functions: std::collections::HashMap<String, fn(&[f64]) -> Result<f64, Error>>,
}

impl ExpressionEvaluator {
    pub fn new() -> Self {
        let mut functions = std::collections::HashMap::new();
        
        // 注册内置函数
        functions.insert("sqrt".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("sqrt".to_string(), 1, args.len()));
            }
            if args[0] < 0.0 {
                return Err(Error::NegativeSquareRoot);
            }
            Ok(args[0].sqrt())
        });
        
        functions.insert("sin".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("sin".to_string(), 1, args.len()));
            }
            Ok(args[0].sin())
        });
        
        functions.insert("cos".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("cos".to_string(), 1, args.len()));
            }
            Ok(args[0].cos())
        });
        
        functions.insert("tan".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("tan".to_string(), 1, args.len()));
            }
            Ok(args[0].tan())
        });
        
        functions.insert("ln".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("ln".to_string(), 1, args.len()));
            }
            if args[0] <= 0.0 {
                return Err(Error::InvalidLogarithm);
            }
            Ok(args[0].ln())
        });
        
        functions.insert("log".to_string(), |args| {
            if args.len() != 2 {
                return Err(Error::InvalidArgumentCount("log".to_string(), 2, args.len()));
            }
            if args[0] <= 0.0 || args[1] <= 0.0 || args[1] == 1.0 {
                return Err(Error::InvalidLogarithm);
            }
            Ok(args[0].log(args[1]))
        });
        
        functions.insert("factorial".to_string(), |args| {
            if args.len() != 1 {
                return Err(Error::InvalidArgumentCount("factorial".to_string(), 1, args.len()));
            }
            let n = args[0] as u64;
            if args[0] < 0.0 || args[0] - n as f64 != 0.0 {
                return Err(Error::InvalidFactorialArgument);
            }
            if n > 20 {
                return Err(Error::FactorialTooLarge);
            }
            Ok((1..=n).product::<u64>() as f64)
        });
        
        Self { functions }
    }
    
    pub fn evaluate(&self, ast: &AstNode) -> Result<f64, Error> {
        match ast {
            AstNode::Number(n) => Ok(*n),
            AstNode::Identifier(ident) => {
                // 处理常量和变量
                match ident.as_str() {
                    "pi" => Ok(std::f64::consts::PI),
                    "e" => Ok(std::f64::consts::E),
                    _ => Err(Error::UndefinedVariable(ident.clone())),
                }
            }
            AstNode::UnaryOp(op, operand) => {
                let value = self.evaluate(operand)?;
                self.evaluate_unary_op(*op, value)
            }
            AstNode::BinaryOp(op, left, right) => {
                let left_val = self.evaluate(left)?;
                let right_val = self.evaluate(right)?;
                self.evaluate_binary_op(*op, left_val, right_val)
            }
            AstNode::FunctionCall(name, args) => {
                let arg_values: Result<Vec<f64>, _> = 
                    args.iter().map(|arg| self.evaluate(arg)).collect();
                let arg_values = arg_values?;
                
                if let Some(func) = self.functions.get(name) {
                    func(&arg_values)
                } else {
                    Err(Error::UndefinedFunction(name.clone()))
                }
            }
        }
    }
    
    fn evaluate_unary_op(&self, op: Operator, value: f64) -> Result<f64, Error> {
        match op {
            Operator::Sqrt => {
                if value < 0.0 {
                    Err(Error::NegativeSquareRoot)
                } else {
                    Ok(value.sqrt())
                }
            }
            Operator::Sin => Ok(value.sin()),
            Operator::Cos => Ok(value.cos()),
            Operator::Tan => Ok(value.tan()),
            Operator::Ln => {
                if value <= 0.0 {
                    Err(Error::InvalidLogarithm)
                } else {
                    Ok(value.ln())
                }
            }
            Operator::Factorial => {
                if value < 0.0 || value.fract() != 0.0 {
                    return Err(Error::InvalidFactorialArgument);
                }
                let n = value as u64;
                if n > 20 {
                    return Err(Error::FactorialTooLarge);
                }
                Ok((1..=n).product::<u64>() as f64)
            }
            _ => Err(Error::InvalidOperator),
        }
    }
    
    fn evaluate_binary_op(&self, op: Operator, left: f64, right: f64) -> Result<f64, Error> {
        match op {
            Operator::Add => Ok(left + right),
            Operator::Subtract => Ok(left - right),
            Operator::Multiply => Ok(left * right),
            Operator::Divide => {
                if right == 0.0 {
                    Err(Error::DivisionByZero)
                } else {
                    Ok(left / right)
                }
            }
            Operator::Power => Ok(left.powf(right)),
            _ => Err(Error::InvalidOperator),
        }
    }
}
}

2.7.6 数据统计模块

#![allow(unused)]
fn main() {
// src/data/mod.rs
pub mod types;
pub mod statistics;

use types::Statistics;

// 重新导出
pub use statistics::Statistics;
}
#![allow(unused)]
fn main() {
// src/data/statistics.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Statistics {
    pub count: usize,
    pub mean: f64,
    pub median: f64,
    pub mode: Vec<f64>,
    pub variance: f64,
    pub std_dev: f64,
    pub min: f64,
    pub max: f64,
    pub sum: f64,
}

impl Statistics {
    pub fn print_detailed(&self) {
        println!("=== 统计信息 ===");
        println!("数据个数: {}", self.count);
        println!("总和: {:.2}", self.sum);
        println!("平均值: {:.2}", self.mean);
        println!("中位数: {:.2}", self.median);
        println!("众数: {:?}", self.mode.iter()
            .map(|&x| format!("{:.2}", x))
            .collect::<Vec<_>>()
            .join(", "));
        println!("最小值: {:.2}", self.min);
        println!("最大值: {:.2}", self.max);
        println!("方差: {:.4}", self.variance);
        println!("标准差: {:.4}", self.std_dev);
        println!("===============");
    }
    
    pub fn get_range(&self) -> f64 {
        self.max - self.min
    }
    
    pub fn get_coefficient_of_variation(&self) -> f64 {
        if self.mean == 0.0 {
            0.0
        } else {
            self.std_dev / self.mean.abs()
        }
    }
}

// 线性回归
pub struct LinearRegression {
    pub slope: f64,
    pub intercept: f64,
    pub r_squared: f64,
}

impl LinearRegression {
    pub fn new(x_data: &[f64], y_data: &[f64]) -> Option<Self> {
        if x_data.len() != y_data.len() || x_data.is_empty() {
            return None;
        }
        
        let n = x_data.len() as f64;
        let sum_x: f64 = x_data.iter().sum();
        let sum_y: f64 = y_data.iter().sum();
        let sum_xy: f64 = x_data.iter().zip(y_data.iter())
            .map(|(&x, &y)| x * y).sum();
        let sum_x2: f64 = x_data.iter().map(|&x| x * x).sum();
        let sum_y2: f64 = y_data.iter().map(|&y| y * y).sum();
        
        let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x);
        let intercept = (sum_y - slope * sum_x) / n;
        
        // 计算 R²
        let ss_tot: f64 = y_data.iter()
            .map(|&y| (y - sum_y / n).powi(2))
            .sum();
        let ss_res: f64 = x_data.iter().zip(y_data.iter())
            .map(|(&x, &y)| {
                let predicted = slope * x + intercept;
                (y - predicted).powi(2)
            })
            .sum();
        let r_squared = 1.0 - (ss_res / ss_tot);
        
        Some(Self {
            slope,
            intercept,
            r_squared,
        })
    }
    
    pub fn predict(&self, x: f64) -> f64 {
        self.slope * x + self.intercept
    }
    
    pub fn print_equation(&self) {
        println!("线性回归方程: y = {:.4}x + {:.4}", self.slope, self.intercept);
        println!("决定系数 (R²): {:.4}", self.r_squared);
    }
}
}

2.7.7 历史记录管理

#![allow(unused)]
fn main() {
// src/history/mod.rs
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Write};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryRecord {
    pub expression: String,
    pub result: f64,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}

pub struct HistoryManager {
    records: Vec<HistoryRecord>,
    max_records: usize,
}

impl HistoryManager {
    pub fn new() -> Self {
        Self::with_capacity(100)
    }
    
    pub fn with_capacity(capacity: usize) -> Self {
        let records = Self::load_from_file().unwrap_or_default();
        Self {
            records,
            max_records: capacity,
        }
    }
    
    pub fn add_record(&mut self, expression: &str, result: f64) {
        let record = HistoryRecord {
            expression: expression.to_string(),
            result,
            timestamp: chrono::Utc::now(),
        };
        
        self.records.push(record);
        
        // 保持记录数量限制
        if self.records.len() > self.max_records {
            self.records.remove(0);
        }
        
        // 保存到文件
        self.save_to_file().ok();
    }
    
    pub fn get_recent_records(&self, count: usize) -> &[HistoryRecord] {
        let start = if self.records.len() > count {
            self.records.len() - count
        } else {
            0
        };
        &self.records[start..]
    }
    
    pub fn search_records(&self, query: &str) -> Vec<&HistoryRecord> {
        self.records
            .iter()
            .filter(|record| 
                record.expression.contains(query) ||
                record.result.to_string().contains(query)
            )
            .collect()
    }
    
    pub fn clear(&mut self) {
        self.records.clear();
        self.save_to_file().ok();
    }
    
    pub fn display(&self) {
        if self.records.is_empty() {
            println!("暂无计算历史");
            return;
        }
        
        println!("=== 计算历史 ===");
        for (i, record) in self.records.iter().enumerate() {
            println!("{}. {} = {}", 
                i + 1, 
                record.expression, 
                record.result
            );
        }
        println!("===============");
    }
    
    fn get_history_file() -> std::path::PathBuf {
        let mut path = dirs::home_dir().unwrap_or_default();
        path.push(".rust_calculator_history.json");
        path
    }
    
    fn load_from_file() -> io::Result<Vec<HistoryRecord>> {
        let path = Self::get_history_file();
        if !path.exists() {
            return Ok(Vec::new());
        }
        
        let file = File::open(path)?;
        let reader = BufReader::new(file);
        
        let records: Vec<HistoryRecord> = serde_json::from_reader(reader)
            .unwrap_or_default();
        
        Ok(records)
    }
    
    fn save_to_file(&self) -> io::Result<()> {
        let path = Self::get_history_file();
        
        // 确保目录存在
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        
        let file = File::create(path)?;
        serde_json::to_writer_pretty(file, &self.records)?;
        
        Ok(())
    }
}
}

2.7.8 错误处理

#![allow(unused)]
fn main() {
// src/utils/mod.rs
pub mod error;

pub use error::Error;
}
#![allow(unused)]
fn main() {
// src/utils/error.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
pub enum Error {
    #[error("除零错误")]
    DivisionByZero,
    
    #[error("负数开平方根: {0}")]
    NegativeSquareRoot,
    
    #[error("无效的对数: 底数必须 > 0 且 ≠ 1, 真数必须 > 0")]
    InvalidLogarithm,
    
    #[error("阶乘参数无效: 必须是非负整数")]
    InvalidFactorialArgument,
    
    #[error("阶乘值过大: n > 20")]
    FactorialTooLarge,
    
    #[error("空数据集")]
    EmptyDataSet,
    
    #[error("无效数字: {0}")]
    InvalidNumber(String),
    
    #[error("无效字符: {0}")]
    InvalidCharacter(char),
    
    #[error("括号不匹配")]
    MismatchedParen,
    
    #[error("无效表达式")]
    InvalidExpression,
    
    #[error("操作数不足")]
    InsufficientOperands,
    
    #[error("无效操作符")]
    InvalidOperator,
    
    #[error("未定义变量: {0}")]
    UndefinedVariable(String),
    
    #[error("未定义函数: {0}")]
    UndefinedFunction(String),
    
    #[error("函数 {0} 参数数量错误: 期望 {1}, 实际 {2}")]
    InvalidArgumentCount(String, usize, usize),
    
    #[error("输入/输出错误: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("JSON 序列化错误: {0}")]
    Json(#[from] serde_json::Error),
    
    #[error("时间处理错误: {0}")]
    Chrono(#[from] chrono::ParseError),
}
}

2.8 练习题

练习 2.1:基础计算器

实现一个基础的四则运算计算器:

  • 支持 +、-、*、/ 操作
  • 处理错误情况(除零等)
  • 提供用户友好的界面

练习 2.2:温度转换器

创建一个温度转换工具:

  • 摄氏度 ↔ 华氏度
  • 摄氏度 ↔ 开尔文
  • 支持批量转换
  • 显示转换历史

练习 2.3:数据分析工具

开发一个简单数据处理器:

  • 读取 CSV 文件
  • 计算基础统计量
  • 找出极值和异常值
  • 生成报告

练习 2.4:单位转换器

设计一个单位转换系统:

  • 长度单位转换(米、厘米、英尺等)
  • 重量单位转换(公斤、磅、盎司等)
  • 温度单位转换
  • 自定义转换函数

练习 2.5:元组数据处理器

创建一个处理元组数据的工具:

  • 解析包含姓名、年龄、成绩的学生信息
  • 实现坐标几何计算(点距离、中点等)
  • 时间处理(小时、分钟、秒的转换)
  • 多值返回函数的练习

练习 2.6:数组数据分析器

开发一个数组数据处理程序:

  • 数组的排序、搜索和统计分析
  • 多维数组操作(矩阵运算)
  • 数组元素的替换和删除
  • 实现经典算法(冒泡排序、二分查找等)

2.9 性能优化建议

2.9.1 数值计算优化

#![allow(unused)]
fn main() {
// 避免重复计算
fn optimized_calculation(data: &[f64]) -> (f64, f64) {
    let n = data.len() as f64;
    let sum: f64 = data.iter().sum();
    let mean = sum / n;
    
    // 一次遍历计算方差
    let variance: f64 = data.iter()
        .map(|&x| (x - mean).powi(2))
        .sum::<f64>() / n;
    
    let std_dev = variance.sqrt();
    (mean, std_dev)
}

// 使用迭代器优化
fn iterator_optimization() {
    let numbers: Vec<i32> = (1..=1000).collect();
    
    // 链式操作
    let result: i32 = numbers
        .iter()
        .filter(|&&x| x % 2 == 0)    // 过滤偶数
        .map(|&x| x * x)             // 平方
        .sum();                      // 求和
    
    println!("偶数平方和: {}", result);
}
}

2.9.2 内存管理优化

#![allow(unused)]
fn main() {
// 预分配容量
fn preallocate_example() {
    let mut numbers = Vec::with_capacity(1000);
    for i in 0..1000 {
        numbers.push(i);
    }
}

// 避免不必要的克隆
fn efficient_cloning() {
    let original = vec![1, 2, 3, 4, 5];
    
    // 使用引用而不是克隆
    let sum: i32 = original.iter().sum();
    
    // 只在需要时克隆
    if sum > 10 {
        let cloned = original.clone();  // 必要时才克隆
        // 使用 cloned
    }
}
}

2.10 本章总结

通过本章学习,你已经掌握了:

核心概念

  1. 变量声明:let、let mut、const 的使用和区别
  2. 基础数据类型:整数、浮点、布尔、字符、字符串
  3. 复合数据类型:元组(不同类型元素的固定集合)、数组(相同类型元素的固定集合)
  4. 控制流:if、loop、while、for、match
  5. 函数:定义、调用、参数、返回值

实战项目

  • 完整的科学计算器实现
  • 表达式解析和求值
  • 数据统计分析功能
  • 历史记录管理

最佳实践

  • 变量命名规范
  • 错误处理策略
  • 性能优化技巧
  • 代码组织方式

下一章预告

  • 所有权和借用系统
  • 内存安全保证
  • 引用和切片
  • 生命周期概念

通过这些基础知识的掌握和实际项目的练习,你已经具备了 Rust 编程的基本能力。接下来将深入学习 Rust 最具特色的所有权系统!