DEEP 121 · 第十一辑 · 服务与训练工具逐函数 · LEARN NOTES

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

解读 121 · chorale.rs(二):曲子数据与调度

解读对象:robotd/src/chorale.rs(1320 行;上篇解读 120已走 1-631 结构主干,本篇读曲子表的消费端、演出收场机制与 633-1320 行的测试)
需要的前置:解读 120(状态机与 tick 主干,必读)、解读 12(合唱机制导览)

120 篇讲清了"谁指挥、坐哪个位";本篇讲剩下两件事:一首曲子从编号到声响要经过哪些函数,以及演出怎么体面收场——然后走进文件的后半:633-1320 行整整 687 行测试,占全文件一半,120 篇尚未拆封。

曲子目录:查询 API 与"即换即载"

曲子表本体(三个 PIECE_* 常量与 PIECES 数组,60-66 行)120 篇已列;它的三个消费函数在本篇:piece(id)(84-91 行)match 出乐谱 Score,known_piece(70-72 行)给命令入口验 --piece,piece_catalogue(75-81 行)把"本机有哪些曲子"拼成拒绝文案。表的关键性质是换曲即换 tempo:heard() 里确认重启后,新建 Follower::new(score.bpm) 并立刻 observe 第一拍(348-356 行)——测试 a_joiner_sings_the_piece_the_beacon_names(1041-1050 行)钉死"加入 duck-strut 演出必须载入它的 126 bpm",否则相位锁数的是错误的拍长。操作者钉曲是一条三级链:激活时 --piece 钉优先,普通激活退回环境变量 DUCK_CHORALE_PIECE,再退回时钟硬币(237-244 行);钉在停用后失效(测试 968-1011 行,"钉子赢一次,硬币回归"),构造时(210-222 行)就把不认识的钉曲过滤掉,不让它经兜底路径变成 panic。

收场:散场阈值、重启与"安静好过错误"

演出终点的三条路构成对称设计:指挥在 position 超过总拍数 +2.0 时散场回 Listening(492 行);跟随者晚到 +6.0(536 行),注释写明这是给"指挥在最后一个和弦里消失"的兜底——健康时永远由指挥的重启带路。重启检测在 326-330 行:曲子编号变了、或拍计数倒退 4–128 拍,都按新演出处理;两个测试分别钉住换曲重启(749-782 行)与同曲倒退重启(787-823 行,旧相位拟合吃到倒退拍会"自由飞行")。重启分支里还有个安静的退路:指挥换了一首本机构不认识的曲子(332-340 行),跟随者直接回 Listening——注释原话 "quiet is better than wrong"(安静好过唱错)。测试 an_unknown_piece_is_declined_not_guessed(1056-1070 行)进一步钉住:面对未知曲子不仅不加入,也不在同一间屋里开第二场——有人唱歌时自己的信标必须保持 idle。

687 行测试:注释先讲事故,断言钉修复

633-1320 行共 20 个测试,是这份文件的验收档案,几个代表:the_conductor_is_followed_across_its_rotating_addresses(1107-1142 行)被注释称为"本特性最糟 bug 的回归测试"——BLE 隐私下地址每几秒轮换,按地址认指挥的跟随者永远锁不上;测试让六个拍子各从全新地址到达,断言照样锁定并领到 Bass 声部。a_duck_sharing_a_register_is_still_a_different_duck(930-963 行)钉 16 位 id 的由来:8 位时代第四只鸭滚了指挥的字节,被全队当成回声吞掉,永远加不进来。the_beacon_is_only_published_when_it_changes(1276-1303 行)钉发布限流:50 Hz 循环、一秒一拍的节拍,"每秒两次 D-Bus 往返与一百次的区别"。a_duck_not_yet_seated_waits_rather_than_guessing(1308-1319 行)钉最后的谦逊:roster 里没你的名字就不唱,猜一个声部就是俩鸭同唱一行。head_expression(617-631 行,曲子位置的纯函数)也被 1017-1035 行钉住:同一拍全队算出同一摇摆,且幅度全部不超过 0.15 rad——头上驮着 ToF,摆大了平衡策略有意见。

你带走的收获

延伸

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