18·复合类型入门

元组与数组

元组与数组

学习目标

  1. 掌握元组的定义和解构
  2. 掌握数组的定义和操作
  3. 理解固定大小和栈分配
  4. 掌握切片操作

核心概念

元组(Tuple)

fn main() {
    // 定义
    let tup: (i32, f64, &str) = (42, 3.14, "hello");

    // 解构
    let (x, y, z) = tup;
    println!("x={}, y={}, z={}", x, y, z);

    // 索引访问
    println!("{}", tup.0);  // 42
    println!("{}", tup.1);  // 3.14
    println!("{}", tup.2);  // "hello"

    // 单元元组(unit type)
    let unit: () = ();
}

元组作为函数返回值

fn div_rem(a: i32, b: i32) -> (i32, i32) {
    (a / b, a % b)
}

fn main() {
    let (quotient, remainder) = div_rem(17, 5);
    println!("17 / 5 = {} 余 {}", quotient, remainder);
}

数组(Array)

fn main() {
    // 固定大小,栈分配
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    let zeros = [0; 10];  // 10 个 0

    // 访问
    let first = arr[0];
    let last = arr[arr.len() - 1];

    // 长度
    println!("len: {}", arr.len());

    // 遍历
    for val in &arr {
        print!("{} ", val);
    }
    println!();

    // 带索引遍历
    for (i, val) in arr.iter().enumerate() {
        println!("arr[{}] = {}", i, val);
    }
}

数组切片

fn main() {
    let arr = [1, 2, 3, 4, 5];

    let slice = &arr[1..3];     // [2, 3]
    let all = &arr[..];         // 整个数组
    let from_two = &arr[2..];   // [3, 4, 5]
    let to_three = &arr[..3];   // [1, 2, 3]

    // 传递给函数(接受 &[T])
    println!("sum: {}", sum(&arr));
    println!("partial sum: {}", sum(&arr[1..4]));
}

fn sum(numbers: &[i32]) -> i32 {
    numbers.iter().sum()
}

多维数组

fn main() {
    let matrix: [[i32; 3]; 2] = [
        [1, 2, 3],
        [4, 5, 6],
    ];

    println!("{}", matrix[0][1]);  // 2
    println!("{}", matrix[1][2]);  // 6
}

数组 vs Vec

特性数组 [T; N]Vec Vec<T>
大小编译时固定运行时动态
存储
性能更快(无堆分配)略慢
适用已知大小未知大小

常用方法

fn main() {
    let arr = [3, 1, 4, 1, 5, 9, 2, 6];

    // 查找
    let pos = arr.iter().position(|&x| x == 5);  // Some(4)
    let found = arr.iter().any(|&x| x > 8);       // true
    let all_positive = arr.iter().all(|&x| x > 0); // true

    // 最值
    let max = arr.iter().max();  // Some(&9)
    let min = arr.iter().min();  // Some(&1)

    // 排序(需要可变)
    let mut arr = [3, 1, 4, 1, 5];
    arr.sort();
    println!("{:?}", arr);  // [1, 1, 3, 4, 5]

    // 反转
    arr.reverse();
    println!("{:?}", arr);  // [5, 4, 3, 1, 1]
}

实践练习

练习 1:旋转数组

fn rotate_left(arr: &mut [i32], k: usize) {
    let n = arr.len();
    let k = k % n;
    arr.reverse();
    arr[..n-k].reverse();
    arr[n-k..].reverse();
}

fn main() {
    let mut arr = [1, 2, 3, 4, 5];
    rotate_left(&mut arr, 2);
    println!("{:?}", arr);  // [3, 4, 5, 1, 2]
}

练习 2:合并有序数组

fn merge_sorted(a: &[i32], b: &[i32]) -> Vec<i32> {
    let mut result = Vec::with_capacity(a.len() + b.len());
    let mut i = 0;
    let mut j = 0;
    while i < a.len() && j < b.len() {
        if a[i] <= b[j] {
            result.push(a[i]);
            i += 1;
        } else {
            result.push(b[j]);
            j += 1;
        }
    }
    result.extend_from_slice(&a[i..]);
    result.extend_from_slice(&b[j..]);
    result
}

fn main() {
    let a = [1, 3, 5, 7];
    let b = [2, 4, 6, 8];
    let merged = merge_sorted(&a, &b);
    println!("{:?}", merged);  // [1, 2, 3, 4, 5, 6, 7, 8]
}

练习 3:矩阵乘法

fn matmul(a: &[[f64; 3]; 3], b: &[[f64; 3]; 3]) -> [[f64; 3]; 3] {
    let mut result = [[0.0; 3]; 3];
    for i in 0..3 {
        for j in 0..3 {
            for k in 0..3 {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    result
}

fn main() {
    let a = [
        [1.0, 2.0, 3.0],
        [4.0, 5.0, 6.0],
        [7.0, 8.0, 9.0],
    ];
    let b = [
        [9.0, 8.0, 7.0],
        [6.0, 5.0, 4.0],
        [3.0, 2.0, 1.0],
    ];
    let c = matmul(&a, &b);
    for row in &c {
        println!("{:?}", row);
    }
}

常见错误

1. 数组越界

let arr = [1, 2, 3];
// let x = arr[10];  // ❌ panic: index out of bounds
let x = arr.get(10);  // ✅ 返回 None

2. 数组大小不匹配

let arr: [i32; 3] = [1, 2, 3];
// let arr2: [i32; 5] = arr;  // ❌ 大小不同

3. 可变借用

let mut arr = [1, 2, 3];
let slice = &arr[0..2];
// arr[0] = 10;  // ❌ 不能在借用期间修改
println!("{:?}", slice);

小结

类型语法特点
元组(T1, T2, ...)不同类型,固定大小
数组[T; N]相同类型,固定大小,栈分配
切片&[T]动态大小引用

元组适合少量异构数据,数组适合同构固定大小序列。

练习编辑器

rust
Loading...