DEEP 190 · 第十六辑 · 小白基础课 · LEARN NOTES

收进学习手册 · 2026-09-11 · duck.whatled.com

解读 190 · Rust 入门(三):trait 与泛型

解读对象:概念课 · 以 duck-control/src/io.rs 的 RobotIo trait 为教材
需要的前置:解读 189(Result 与 ?)

这只鸭子有三套"身体":真机 XL330 总线、换装后的飞特 HL-2915 总线、电脑里的 MuJoCo 仿真。控制循环只有一套,凭什么都能跑?答案是 trait——同一张合同,多个承包商。

合同本身:RobotIo

trait 是一份"能力清单":谁签了字,谁就必须会做清单上的事。io.rs:113-116:

pub trait RobotIo {
    /// One transaction: joints and IMU together.
    fn read(&mut self) -> Result<Sensors>;
    fn write(&mut self, targets: &JointTargets) -> Result<()>;

白话:合同写明"必须会 read(一次事务把 15 个关节和 IMU 一起读回)"、"必须会 write",后面还有 set_gain、set_torque、reboot、slow_sensors 等条款(全六方法见解读 106)。注意 read 的返回值正是上一篇的 Result<Sensors>——合同连"失败怎么交代"都规定了。

三个(半)承包商

合同是抽象的,干活的是具体类型,各自用 impl RobotIo for X 签字:

每个承包商内部天差地别(寄存器地址、帧格式全不同),但对上只交一张答卷:fn read(&mut self) -> Result<Sensors>。合同还允许"默认条款"——签了字就自动拥有,不想要才自己重写。io.rs:164:

fn imu_ready(&self) -> bool {
    true
}

泛型:同一套代码,编译时定承包商

合同签了,谁来用?看主循环的签名(robotd/src/main.rs:1826):async fn control_loop<T: RobotIo>(io: T, ...)。<T: RobotIo> 读作"任意类型 T,只要它签过 RobotIo 这张合同"。安全层同理(duck-control/src/safety.rs:105):

pub struct Safety<T: RobotIo> {
    io: T,

Safety 不关心手里是真舵机还是仿真,反正 T 都会那六个方法。编译器按实际传入的类型各生成一份专用机器码——抽象没有运行时开销。真正的点睛之笔是钥匙只发一把:解读 188讲过 io 被移交给 Safety 后别处再无副本,"任何电机命令必须过安全层"由编译器背书。

你带走的收获

延伸

什么鸭 WHATDUCK · 复刻学习笔记 ← 全部手册 · 首页