Rust 1.100 beta 的 Vec::from_fn 撞上扩展 trait,编译报 expected usize
Rust 1.100 beta 新 Vec::from_fn 抢先解析旧 trait 同名调用,出现 E0308。用完全限定路径保留原实现,再判断长度与索引迁移。
项目此前用扩展 trait 提供 Vec::from_fn,切到 Rust 1.100 beta 后,旧调用突然报 E0308:expected usize, found u32。先看诊断中的函数定义位置;如果它已经指向标准库 Vec,就不再是原来的 trait 实现。
1.100 beta 加入了 Vec 的固有关联函数 from_fn(length: usize, f: FnMut(usize) -> T)。同名调用现在会优先解析到这份实现,因此旧扩展函数的参数类型与生成规则都需要重新确认。这里讨论 beta 升级预检,不把它写成 Rust 1.99 正式版新出现的回归,也不保证 beta 接口之后不会变化。
明确调用原 trait,而不是先把 u32 改成 usize
如果仍要保留项目的生成语义,用完全限定语法指定原来的 trait:
let values = <Vec<Item> as ProjectVecFactory<Item>>::from_fn(count, make_item);
这是一段调用形式,Item、ProjectVecFactory、count 和 make_item 要替换为项目现有类型、trait 与参数。真正的 trait 可能没有泛型参数,函数也可能有不同签名,不能把上例名称当作标准库接口直接导入。
下面用一个完整的小型扩展说明这种消歧方式,它不是要求替换原业务实现:
trait IndexedVec<T> {
fn from_fn<F: FnMut(u32) -> T>(count: u32, f: F) -> Vec<T>;
}
impl<T> IndexedVec<T> for Vec<T> {
fn from_fn<F: FnMut(u32) -> T>(count: u32, f: F) -> Vec<T> {
(0..count).map(f).collect()
}
}
fn main() {
let values = <Vec<u32> as IndexedVec<u32>>::from_fn(3, |i| i + 10);
assert_eq!(values, vec![10, 11, 12]);
}
完全限定路径让编译器选择 IndexedVec 对 Vec 的实现,不再与固有函数争用简写名字。它适合保留现有行为;长期维护时,也可以给项目函数换一个更具体的名称,并同步所有调用点。
有意迁移到标准库时,逐项对齐生成规则
若决定使用新的 Vec 固有函数,确认长度类型为 usize,闭包接收的是从零开始的 usize 索引,返回元素类型也与原接口一致。原 trait 可能接收 u32、忽略索引、按其他范围生成,或包含额外初始化逻辑。仅按编译器建议转一次整数,不会自动保留这些行为。
来自外部数据的长度还要处理平台范围与业务上限,不能直接加 as usize 或不加判断地 unwrap 转换结果。长度能转换也不表示允许分配这么多元素;这份内存约束与名字冲突是两个检查。
升级前保存工具链与依赖锁定,先在 beta 检查分支核对实际 rustc --version、完整 E0308 位置以及生成结果。验收应比较元素数量、内容、索引边界和闭包调用规则,并覆盖项目支持的旧稳定工具链。完全限定的 trait 写法可以保持旧入口明确;只有确认新固有函数符合需求后,才移除旧扩展,不能只以编译通过作为迁移完成。


