【Rust】Rust数组和Vec安全读写笔记

Rust基础用法

数组操作

初始化数组

由于 Rust 数组是固定大小的栈上结构,不能"清空"长度,但可以重写所有元素。

推荐方式一:直接赋值新数组(最简洁高效)
rust 复制代码
fn main() {
    let mut arr: [u8; 4] = [1, 2, 3, 4];
    println!("1:{:?}", arr);   // 1:[1, 2, 3, 4]
    // 复位为全 0
    arr = [0; 4];
    println!("2:{:?}", arr);   // 2:[0, 0, 0, 0]
    // 复位为全 false(bool 数组)
    let mut flags: [bool; 4] = [true, false, true, false];
    println!("3:{:?}", flags); // 3:[true, false, true, false]
    flags = [false; 4];
    println!("4:{:?}", flags); // 4:[false, false, false, false]
}

优点:

复制代码
* 编译器会优化为 memset 或向量化指令
* 代码清晰、无 unsafe
* 适用于任何实现了 Copy 的类型(u8, i32, bool, f64 等)
推荐方式二:使用 fill() 方法(Rust 1.50+)
rust 复制代码
fn main() {
    let mut arr = [10u8, 20, 30, 40];
    println!("初始化:{:?}",arr);    // 初始化:[10, 20, 30, 40]
    arr.fill(0); // 所有元素设为 0
    println!("复位后:{:?}",arr);    // 复位后:[0, 0, 0, 0]

    let mut valid = [true, false, true];
    println!("初始化:{:?}",valid);  // 初始化:[true, false, true]
    valid.fill(false);
    println!("复位后:{:?}",valid);  // 复位后:[false, false, false]
}

✅ 优点:

语义明确:"填充为某值"

适用于任何 Clone 类型(不仅限于 Copy)

比手动循环更安全高效

推荐方式三:使用 iter_mut().for_each()(灵活性高)
rust 复制代码
fn main() {
    let mut arr = [1, 2, 3, 4];
    arr.iter_mut().for_each(|x| *x = 0);

    // 或重置为不同逻辑(如递增)
    arr.iter_mut().enumerate().for_each(|(i, x)| *x = i as u8);
}

仅在需要非统一值时使用,否则优先用 fill() 或直接赋值。

读/写数组

最佳实践:默认用 get / get_mut;仅在性能关键且逻辑确保安全时用直接索引或 unsafe。

操作 安全方法 返回类型 是否 panic
读取 .get(i) Option<&T>
写入 .get_mut(i) Option<&mut T>
直接索引 arri / arri = v T / () 是(越界时)
极速访问 get_unchecked(_mut) &T / &mut T 否(但 UB 风险)

读取 → 用 get().and_then(...),安全且无 panic
写入 → 必须用 get_mut().and_then(...),并解引用赋值:*elem = value。

一维数组

在 Rust 中,一维数组(或切片、Vec)的安全读写是指:
读取 时不会因越界而 panic;
写入时既能避免越界,又能获得可变引用。

安全读取(只读)

方法:使用 .get(index)

rust 复制代码
let arr = [10, 20, 30];
if let Some(&value) = arr.get(1) {
    println!("arr[1] = {}", value); // 安全读取
}
// 若索引越界(如 arr.get(5)),返回 None,不会 panic

适用于:数组 T; N,切片 &T,Vec

返回类型是 Option<&T>,需用 match、if let 或 unwrap_or 等处理。

安全写入(修改)

方法:使用 .get_mut(index)

rust 复制代码
let mut vec = vec![1, 2, 3];
if let Some(elem) = vec.get_mut(1) {
    *elem = 99; // 安全修改
}
// vec 现在是 [1, 99, 3]

同样适用于:mut T; N,&mut T,Vec

返回 Option<&mut T>,解引用后即可赋值。

二维数组

固定大小多维数组

声明形如 \[T; COLS; ROWS],访问、修改、遍历都用双重索引即可。

声明与初始化:let mut mat: [[i32; 4]; 3] = [[0; 4]; 3];

访问单个元素:let elem = mat[1][2];

修改单个元素:mat[0][0] = 1;
嵌套遍历:

rust 复制代码
for row in &mat { 
    for &elem in row { 
        print!("{} ", elem); 
    } 
    println!(); 
}

越界访问会在运行时 panic,若需安全访问可用 get() 返回 Option:
安全取值(不 panic)

rust 复制代码
if let Some(row) = mat.get(1) {
    if let Some(&val) = row.get(2) {
        println!("mat[1][2] = {}", val);
    }
}

**对于固定大小数组 \[i32; N; M]:**安全赋值

rust 复制代码
if let Some(row) = mat.get_mut(i) {
    if let Some(elem) = row.get_mut(j) {
        *elem = 42;
    }
}

注意:必须使用 get_mut() 才能获得 Option<&mut T>,然后通过 *elem = ... 赋值。

动态多维数组(Vec)

行、列可在运行时决定,访问方式与上面完全一样,只是创建方式不同:

声明:let mut mat = vec!vec!\[0; cols; rows];

用法与上面完全一样:mat[i][j]、mat.get(i).and_then(|r| r.get(j)) 等。

rust 复制代码
let mut mat = vec![vec![0; cols]; rows];
mat[0][0] = 1;
for row in &mat {
    for &elem in row {
        print!("{} ", elem);
    }
    println!();
}

正确的赋值方式

rust 复制代码
if let Some(row) = mat.get_mut(i) {
    if let Some(elem) = row.get_mut(j) {
        *elem = 42;
    }
}
科学计算场景:ndarray

若做矩阵运算,可直接用 Array2:

rust 复制代码
use ndarray::Array2;
let mut a = Array2::<usize>::zeros((2, 3));
a[[0, 1]] = 42;              // 直接双索引
for row in a.rows() {        // 按行迭代
    println!("{:?}", row);
}

固定大小用 \[T; N; M],动态用 Vec<Vec>,科学计算用 ndarray::Array2;访问语法都是 arrij 或 arr\[i, j],配合 get() 可避免 panic。

三维数组

在 Rust 中安全地读写三维数组(无论是固定大小的 \[\[T; N; M]; P] 还是动态的 Vec<Vec<Vec>>),核心原则是:
逐层使用 .get() / .get_mut(),并通过 and_then 或嵌套 if let 安全解包,避免越界 panic。

固定大小三维数组(如 \[\[i32; 4; 3]; 2])

安全读取

rust 复制代码
let arr: [[[i32; 4]; 3]; 2] = [[[0; 4]; 3]; 2];

// 方法一:链式 and_then
let value = arr.get(0)
    .and_then(|patch| patch.get(1))
    .and_then(|row| row.get(2));

match value {
    Some(&v) => println!("arr[0][1][2] = {}", v),
    None => println!("Index out of bounds"),
}

安全写入

rust 复制代码
let mut arr: [[[i32; 4]; 3]; 2] = [[[0; 4]; 3]; 2];

// 使用 get_mut 链式
if let Some(plane) = arr.get_mut(0) {
    if let Some(row) = plane.get_mut(1) {
        if let Some(elem) = row.get_mut(2) {
            *elem = 42;
        }
    }
}
// 注意:不能用 and_then 写入,因为 and_then 消费值,而我们需要可变引用链
动态三维数组(Vec<Vec<Vec>>)

创建
let mut arr = vec![vec![vec![0i32; 4]; 3]; 2]; // 2x3x4
安全读取(同上)

rust 复制代码
let value = arr.get(0)
    .and_then(|p| p.get(1))
    .and_then(|r| r.get(2));

安全写入(嵌套 if let)

rust 复制代码
if let Some(p) = arr.get_mut(0) {
    if let Some(r) = p.get_mut(1) {
        if let Some(e) = r.get_mut(2) {
            *e = 100;
        }
    }
}

封装成通用函数(推荐)

为避免重复样板代码,可写辅助函数:

rust 复制代码
fn safe_get_3d<T>(
    arr: &[Vec<Vec<T>>],
    p: usize, m: usize, n: usize) -> Option<&T> {
    arr.get(p)?.get(m)?.get(n)
}

fn safe_set_3d<T>(
    arr: &mut [Vec<Vec<T>>],
    i: usize, j: usize, k: usize,
    value: T) -> Result<(), ()> {

    if let Some(p) = arr.get_mut(i) {
        if let Some(r) = p.get_mut(j) {
            if let Some(e) = r.get_mut(k) {
                *e = value;
                return Ok(());
            }
        }
    }
    Err(())
}

fn main() {
    let mut arr = vec![vec![vec![0i32; 4]; 3]; 2];
    let data = [[[ 1, 2, 3, 4],
                 [ 5, 6, 7, 8],
                 [ 9,10,11,12]], 
                [[20,21,22,23],
                 [24,25,26,27],
                 [28,29,30,31]]];
    for p in 0..2{
        for m in 0..3{
            println!("data[{}][{}]={:?}", p, m, data[p][m]);
            for n in 0..4{
                let _ = safe_set_3d(&mut arr, p, m, n, data[p][m][n]);
            }
        }
    }
    println!("arr={:?}", arr);
    if let Some(v) = safe_get_3d(&mut arr, 0, 1, 2){
        println!("v={}", v);
    }
}

执行结果:

复制代码
data[0][0]=[1, 2, 3, 4]
data[0][1]=[5, 6, 7, 8]
data[0][2]=[9, 10, 11, 12]
data[1][0]=[20, 21, 22, 23]
data[1][1]=[24, 25, 26, 27]
data[1][2]=[28, 29, 30, 31]
arr=[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[20, 21, 22, 23], [24, 25, 26, 27], [28, 29, 30, 31]]]
v=7
相关推荐
泯泷12 分钟前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
泯泷12 分钟前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
独孤留白8 小时前
从C到Rust:Rust 的 Trait 不是Interface,那是什么?
rust
花褪残红青杏小16 小时前
Rust图像处理第7节-马赛克像素化:分块取平均色实现打码风格
rust·webassembly·图形学
doiito1 天前
【Agent Harness】Gliding Horse 设计细节 -- 不跟风开发自己的AI Agent
架构·rust·agent
doiito1 天前
【Agent Harness】Gliding Horse 核心设计理念,不跟风开发自己的AI Agent
ai·rust·架构设计·系统设计·ai agent
花褪残红青杏小2 天前
Rust图像处理第6节- 均值模糊 & 中值模糊:3×3 邻域的两种经典玩法
rust·webassembly·图形学
子兮曰2 天前
前端工具链的「Rust 化」:一场没有赢家的军备竞赛?
前端·后端·rust
星栈2 天前
写 Dioxus Demo 不难,难的是把它写成项目
前端·rust·前端框架
mCell2 天前
【锐评】桌面端技术营销:别拿跑分当工程判断
前端·rust·electron