症状
同一片代码区域产生两种错误,区分它们决定一切:E0706 是 1.75 之前的语法缺口(trait 里根本不能声明 async fn);E0038 是 dyn 兼容性问题(async 方法让 trait 不再对象安全)。底层事实是:async fn 脱糖为返回 impl Future 的方法,返回位置 impl Trait 是不透明的——每个实现返回一个尺寸与布局都不同的匿名类型;vtable 需要一个固定签名,装不下按实现而异的返回类型,而泛型分发可以单态化。这就是 1.75 的能力边界:trait 内 async fn 对泛型可用、对 dyn 不可用。泛型调用全绿、Box
诊断思路
先分辨手里是哪个错误码:E0706 升级工具链即可消失,E0038 需要装箱模式;再确认实际需要的分发方式——grep 所有 dyn 调用点,全部是泛型就不需要 dyn 兼容,存在异构集合(Vec<Box
根因
async fn 返回由具体实现决定尺寸与布局的匿名 future 类型。trait 对象分发要求每个方法都能经 vtable 以单一签名调用,而按实现而异的不透明返回类型塞不进那个槽位——语言要么整体拒绝(1.75 前),要么在 dyn 分发下拒绝(1.75 后)。
修复与验证
按分发需求分流:泛型调用点用原生 async fn in traits(1.75+,零开销单态化);异构分发用 async_trait 宏或手写 Pin<Box
代码示例
error[E0706]: functions in traits cannot be declared async
error[E0038]: the trait `Fetcher` is not dyn-compatible because
method `fetch` is async
trait Fetcher {
async fn fetch(&self, url: &str) -> Vec<u8>; // fine for generics
}
async fn load<F: Fetcher>(f: &F) -> Vec<u8> { f.fetch("...").await }
use async_trait::async_trait;
#[async_trait]
trait FetcherDyn: Send + Sync {
async fn fetch(&self, url: &str) -> Vec<u8>; // returns BoxFuture
}
let fetchers: Vec<Box<dyn FetcherDyn>> = vec![Box::new(Http), Box::new(Mock)];
type FetchFuture = Pin<Box<dyn Future<Output = Vec<u8>> + Send + '_>>;
trait FetcherDyn {
fn fetch(&self, url: &str) -> FetchFuture;
}