直接回答:Pin 承诺所指对象不再移动(内存地址固定),使自引用结构(字段指向同结构内另一字段)和 async 状态机成为可能——Future 编译后就是跨 await 点持引用的自引用结构,await 要求它钉住不动。pin projection 是钉住之后访问字段的问题:Pin<&mut Struct> 要分别投影成字段的 Pin<&mut Field>(结构性字段)或 &mut Field(非结构性),手写 unsafe 易错,pin-project-lite 用宏安全生成。

展开解析:理解链条:移动会改变地址 → 自引用内部指针失效 → 所以要 Pin 禁止移动。Pin 的保证只对“移动敏感”类型成立,类型实现 Unpin(大多数类型,含所有不持内部引用的)则 Pin 形同虚设可随意拆装——这是关键设计:Pin 的成本只落在真正需要的类型上。projection 的不变量三条:结构性字段一旦投影成 Pin 就必须始终被当 Pin 对待(不能中途给普通 &mut);Drop 实现里不能把字段移出;类型不能越出声明的 Unpin 边界。手写易错点:忘了析构时移动字段、把整个结构当 Unpin 处理导致钉住承诺作废。实战场景:手写 Future(少见,多数用 async 块)、实现 stream/迭代器式自引用缓冲(如同时持有 buffer 与指向其内的游标)。替代方案想清楚再 Pin:索引代替指针(游标存 offset)、ouroboros/self_cell 宏封装成熟模式、分两个结构用所有权代替自引用——能绕开就别手写 unsafe projection。

追问方向:为什么 async block 生成的类型不实现 Unpin?Box::pin 与栈上 pin_mut 的区别?

(约 490 字)