Rust中如何消除指向同一类型的关联类型歧义?
关联Trait中重复定义ID类型引发的类型匹配问题
我有一组相互关联的Trait,其中的关联类型都是枚举。为了避免<<World as World>::Exit as Exit>::SpotId这类深层嵌套的全限定名,我在所有需要的Trait里都重复定义了Id相关的关联类型,但现在在实现依赖这些顶层Trait的逻辑时,出现了类型混淆的问题:
trait Accessible { type Context: Ctx; fn can_access(&self, ctx: &Self::Context) -> bool; } trait Id: Copy + Clone + Debug + Eq + Hash + Ord + PartialOrd {} trait Location: Accessible { type LocId: Id; type ExitId: Id; } trait Exit: Accessible { type ExitId: Id; type SpotId: Id; type LocId: Id; } trait World { type Context: Ctx; type Location: Location; type Exit: Exit; type SpotId: Id; fn get_neighbors(&self, spot_id: Self::SpotId) -> &[Self::SpotId]; } trait Ctx: Clone + Eq { type World: World<Context = Self, SpotId = Self::SpotId>; type SpotId: Id; } fn expand<T>(world: &impl World<Context = T>, ctx: &T, start: <T as Ctx>::SpotId) where T: Ctx, { for spot in world.get_neighbors(start) { } }
这段代码在调用world.get_neighbors时出现如下错误:
| expected `World::SpotId`, found `Ctx::SpotId` = note: expected associated type `<impl World<Context = T> as World>::SpotId` found associated type `<T as context::Ctx>::SpotId`
其他使用SpotId的场景也会出现类似的反向类型不匹配错误。
有没有一种简洁的方式,既能保留这些Trait之间的关联关系,又能给SpotId这类类型提供统一的简单名称,让不管从哪个Trait里引用的SpotId都不会产生类型不匹配的问题?
我试过在Trait里添加更多注解,明确要求这些类型必须是同一类型:
trait World { type Context: Ctx<SpotId = Self::SpotId, World = Self>; type Location: Location + Accessible<Context = Self::Context>; type Exit: Exit<SpotId = Self::SpotId> + Accessible<Context = Self::Context>; type SpotId: Id; }
但还是报同样的错误。
我还参考过相关讨论,里面建议用类型别名来管理全限定名,但不确定具体该怎么实现。
更新:我发现可以通过新增类型参数来指定某一类型同时满足两种Trait的要求:
fn expand<T, S>(world: &impl World<Context = T, SpotId = S>, ctx: &T, start: S) where T: Ctx<SpotId = S>, S: Id, { for spot in world.get_neighbors(start) { } }
但随着项目推进,函数签名会变得越来越臃肿,比如:
fn explore<T, S, L, E>( world: &impl World< Context = T, SpotId = S, Exit = impl Exit<ExitId = E, SpotId = S> + Accessible<Context = T>, Location = impl Location<LocId = L> + Accessible<Context = T>, >, ctx: &T, ) where T: Ctx<SpotId = S, LocationId = L, ExitId = E> + Debug, S: Id, L: Id, E: Id, { ... }
而且每当新增其他ID类型时,所有调用这个函数的地方都需要修改(为了简洁,这里省略了更多ID类型)。我希望能从Trait层面找到解决方案。
内容的提问来源于stack exchange,提问作者Zannick
相关产品推荐
相关产品推荐

