RustInPractice(27):动态规划与系列回顾
动态规划把重叠子问题保存为状态表:先定义状态,再写转移,再决定初始化和遍历顺序。它也是 RustInPractice 主线的收官篇。 对应 dynamic_programming。TUI 番外将另行发布。 Fibonacci 只保留前两个状态,将空间从 O(n) 降至 O(1)。0/1 背包一维表必须逆序遍历容量,防止同一物品被重复选择。LCS demo 按 UTF-8 bytes 计算,非 ASCII 的“字符级 LCS”需要不同表示。 当前背包 demo 假设容量非负、weights/values 等长且权重有效;真实 API 应先验证这些输入,避免负数转 usize 或数组越界。 主线至此完成:基础与 Cargo,所有权类型系统,工程并发,最后落到服务、存储和算法。下一步可以继续 TUI 番外,或以一个带测试、配置、数据库和 HTTP 的 capstone 收束实践。 RustInPractice 主线第 27 篇完结。
RustInPractice(26):排序与字符串搜索
排序 demo 用 &mut [i32] 直接操作切片,搜索 demo 用字节序列实现朴素匹配与 KMP。它们适合理解复杂度,生产代码仍应优先标准库。 对应 sorting、string_search。下一篇:动态规划与系列收官。 冒泡和插入排序是 O(n²),快速排序平均 O(n log n),但最后元素 pivot 对已排序输入会退化并导致深递归。默认应使用 sort_unstable(),除非需要稳定排序。 KMP 的 LPS 表让失配后不必回退 haystack,因此复杂度为 O(m+n)。当前实现按 UTF-8 字节搜索,返回字节偏移;非 ASCII 文本不能把该值当字符索引或随意切片。 测试必须覆盖空 slice、单元素、重复值、空 pattern 和 Unicode 边界。 下一篇:动态规划与 RustInPractice 主线回顾。
RustInPractice(25):数据结构与所有权边界
手写数据结构的最大收获不是替代标准库,而是看清所有权如何塑造节点关系。链表和 BST 用 Option<Box<Node>> 表达唯一递归所有权;图用邻接表表达多个边关系。 对应 stack_queue_list、tree、graph、hash_table。 BST 插入的关键是沿着唯一的可变路径递归: 1fn insert(root: &mut Option<Box<TreeNode>>, value: i32) { /* ... */ } 图的 BFS 使用 VecDeque 队列,DFS 用 visited set 防环。自定义 HashMap 使用链地址法展示碰撞,但没有 resize/remove,不能替代标准库。 选择原则:业务优先标准集合;自定义结构只在需求、学习或性能测量证明需要时出现。 下一篇:排序与字符串搜索。
RustInPractice(24):SQLite 与 rusqlite
rusqlite 用 Rust 类型包装 SQLite 的连接、参数绑定、查询和事务。核心规则是:SQL 值永远通过参数绑定传递,不用字符串拼接。 对应 database/sqlite3。下一篇:数据结构。 1234conn.execute( "INSERT INTO students (class_id, name, score) VALUES (?1, ?2, ?3)", params![1, name, score],)?; query_map 将行映射为 struct,? 将数据库失败传播到调用边界。事务应使用 checked transaction,并同时演示 commit 与 rollback;当前 demo 使用内存数据库和 unchecked_transaction(),只适合作为 API 导览。 真实项目还应启用 foreign keys、维护 migration、测试约束、使用持久路径,并决定连接是否只能在同步线程中使用。 下一篇:数据结构在 Rust 中的所有权边界。
RustInPractice(23):WebSocket 与异步流
WebSocket 在 HTTP upgrade 后保持双向消息通道。tokio-tungstenite 将连接同时实现 Stream 与 Sink,接收用 next().await,发送用 send().await。 对应 networking/websocket。下一篇:SQLite。 1234while let Some(message) = ws.next().await { let message = message?; ws.send(Message::Text("Echo: hello".into())).await?;} 服务端通常为每条连接 spawn 一个 task,连接结束后 task 自动结束。需要显式处理 text、binary、ping、pong、close 和错误;demo 将 binary 转成文本提示,因此它是文本 echo,不是保留二进制 payload 的 echo 服务。 accept 循环也不应静默吞掉 listener 错误。生产服务还需要连接上限、超时、认证和关闭协议。 ...
RustInPractice(22):用 Axum 写 JSON API
Axum 将路由、提取器和返回值组合成类型安全的 HTTP API。demo 用 Router、Json 和共享状态完成一个最小用户接口。 对应 networking/http_json。下一篇:WebSocket 与异步流。 路由与提取器123Router::new() .route("/users", get(list_users).post(create_user)) .route("/users/:id", get(get_user)) State(store) 取得应用状态,Path(id) 解析路径参数,Json(body) 反序列化请求体。handler 返回 Json<T>,Serde 负责序列化。 状态与错误demo 用 Arc<Mutex<HashMap<...>>> 保存内存数据,锁只在同步读取或写入期间持有,绝不能跨 .await。真实 API 应增加输入验证、201 Created、结构化错误体、稳定排序和 handler 集成测试。 这个 st...
YOLO 目标检测实战(02):预训练模型冒烟推理
目标:在正式训练之前,先用官方预训练权重对样例图跑一次检测,确认 GPU 推理链路是通的。这一步花不了几分钟,却能把「环境没配对」和「训练超参没调好」这两类问题彻底分开。 这是「YOLO 目标检测实战」的第 02 篇。完整目录见 00 · 系列导读。 一、前置条件 已完成 01 · 环境搭建; 存在预训练 s 档权重(如 weights/yolo_s.pt)与 data/images/(由 scripts/00_download_assets.sh 准备)。 二、执行容器内: 1bash scripts/01_smoke_detect.sh 等价于: 1234567yolo detect predict \ model=/workspace/weights/yolo_s.pt \ source=/workspace/data/images \ device=0 \ project=/workspace/runs/detect \ name=smoke \ exist_ok=True 三、产物可视化结果写到: 1runs/detect/smoke/ 打开...
多模态微调实战(03):从 LMDB 到 JSONL 的数据准备
多模态微调里,数据格式比模型名字更容易卡住人。ms-swift 期望的是「对话 JSONL + 图片路径」,而公开 OCR 数据集常常是 LMDB / TFRecord 等离线格式,中间需要一层转换。这一篇讲怎么把数据整理成训练框架能直接吃的样子。 这是「多模态微调实战」的第 03 篇。环境就绪后,数据是下一个门槛。 一、数据从哪来本系列任务使用 ModelScope 上的车牌 OCR 数据(公开集,示例名:ocr_plate): 完整规模大约:训练 37 万 + 验证 4 万; 原始形态多为 LMDB(图像二进制 + 标签字符串); 建议流程:先转一个小子集验证,再转全量。 二、LMDB 里大概长什么样常见键设计(示意): 123num-samples -> 样本总数image-000000001 -> 图片二进制label-000000001 -> 车牌字符串(UTF-8) 转换时要约定: 图片导出到哪里; JSONL 里写相对还是绝对路径(容器内建议统一成 /workspace/...); 用...
RustInPractice(21):CLI、配置、日志与错误边界
语言特性最终要落到程序入口。一个可靠 CLI 应将参数解析、配置读取、业务逻辑、日志和错误呈现分层,使核心代码可测试、命令行只是薄薄的一层适配器。 RustInPractice 第三季收官篇。对应 demo:learning_guide、argv_demo、filesystem_demo。第四季将进入 Axum、WebSocket、SQLite 与算法实践。 一、用 Clap 声明命令结构12345#[derive(clap::Subcommand)]enum Commands { List, Demo { name: String },} learning_guide 将 subcommand 解析后交给 demos::run。入口只负责输入适配,模块负责业务行为,这让同一逻辑既能被 CLI 调用,也能被测试直接调用。 二、配置来源要有优先级常见顺序是:命令行参数 > 环境变量 > 配置文件 > 安全默认值。不要把密钥写进默认值、示例输出或日志;示例使用 user@example.com、<T...
RustInPractice(20):限流、背压与后台任务
每个请求都 spawn 一个任务看起来很轻松,但高峰时会把内存、连接和下游服务推向失控。生产级异步系统的关键不是“能并发”,而是“知道什么时候必须慢下来”。 RustInPractice 第 20 篇。对应 demo:concurrency/thread_pool。下一篇用 CLI、配置、文件和日志组织一个真实入口。 一、demo 实际是什么?TaskPool 使用 tokio::sync::Semaphore: 12let _permit = semaphore.acquire().await?;run_task().await; 它限制同一时刻运行的任务数量,但每个提交仍会创建 Tokio task。因此它准确的名称是异步并发限制器,不是固定 worker 线程池。真正 worker pool 通常还需要有界 channel、固定 worker 集合和关闭协议。 二、背压策略必须可见队列或 semaphore 满时,系统可以: 策略 结果 等待 提高延迟,保护下游 拒绝 快速返回,调用方重试或降级 超时 避免无限等待 丢弃 只适合可丢失事件 ...















