疑问:为何无法使用带未推断泛型参数的Trait关联类型?
关于Rust错误E0212的疑问解答
问题背景
我参考Rust错误索引中的E0212示例,还是没搞懂报错原因,相关代码如下:
#![allow(unused)] fn main() { pub trait Foo<T> { type A; fn get(&self, t: T) -> Self::A; } fn foo2<I: for<'x> Foo<&'x isize>>(field: I::A) {} // error! }
疑问:为什么不能使用带有未推断泛型参数的Trait关联类型?
原因解析
核心问题出在关联类型A和泛型参数T的绑定关系上:
- 定义
trait Foo<T>时,关联类型A是依赖于泛型参数T的——也就是说,同一个实现类型I,当T取不同值(比如生命周期不同的&'x isize和&'y isize)时,对应的A可能是完全不同的类型。 - 而在
foo2的签名里,for<'x> Foo<&'x isize>这个约束要求I对所有生命周期'x都实现Foo<&'x isize>。但此时I::A并没有绑定到某一个具体的T(也就是某一个确定生命周期的&'x isize),编译器根本不知道你指的是哪一个T对应的A——毕竟不同T对应的A可能不一样,编译器无法推断出唯一的类型。
举个实际的例子,如果有这样的实现:
struct Bar; impl Foo<&'static isize> for Bar { type A = u32; fn get(&self, t: &'static isize) -> u32 { *t as u32 } } impl Foo<&'_ isize> for Bar { type A = i64; fn get(&self, t: &isize) -> i64 { *t as i64 } }
这里Bar满足for<'x> Foo<&'x isize>的约束,但它对应不同T的A分别是u32和i64,那foo2里的field: I::A到底是要u32还是i64?编译器完全没法确定,所以只能报错。
如果要解决这个问题,你需要明确把A和某个具体的T绑定,或者调整设计让A不依赖于T。比如:
// 方式1:让A不依赖T,将A设为trait的泛型参数 pub trait Foo<T, A> { fn get(&self, t: T) -> A; } fn foo2<I, A>(field: A) where I: for<'x> Foo<&'x isize, A> {}
或者如果A必须依赖T,就要明确指定对应的T:
// 方式2:绑定到具体的T对应的A fn foo2<I>(field: <I as Foo<&'static isize>>::A) where I: Foo<&'static isize> {}
内容的提问来源于stack exchange,提问作者masion
相关产品推荐
相关产品推荐

