此示例已简化。
我有一组这样的课程:
case class KeyMapping[KeyType](k:KeyType)
class WrappedMapping[KeyType](m:T forSome {type T <: KeyMapping[KeyType]}) {
val k:KeyType = ???
}
在以下代码中,正确推断出类型:
val w = new WrappedMapping(KeyMapping("key"))
//The statement below gives the correct error
//type mismatch;
// found : w.k.type (with underlying type String) required: Nothing
//val test1:Nothing = w.k
我不知道如何正确推断以下类型:
class Mappings[KeyType, L <: HList](mappings:L) {
val k:KeyType = ???
}
val m = new Mappings(KeyMapping("key1") :: KeyMapping("key2") :: HNil)
// should not compile, k should be of type String
val test2:Nothing = m.k
我是否可以根据KeyType
的内容推断HList
?
答案 0 :(得分:8)
Shapeless提供了一个隐含的ToList
,毫不奇怪,它将HLists转换为Lists。
为了做到这一点,它必须首先计算HList中类型的LUB(最小上限),这是你可以使用的东西:
import shapeless.ops.hlist.ToList
class Mappings[L <: HList, Lub](mappings:L)(implicit toList: ToList[L, Lub]) {
...
}
L
进入后,隐式解决方案会发现一个(且唯一的)有效ToList
实例受L
约束,Lub
类型被拉出。< / p>
这还不够,因为Lub
将是KeyMapping[String]
,而您想要的只是String
部分。像往常一样,无形,解决方案是添加另一个隐含的:
class Mappings[L <: HList, Lub, KeyType](mappings:L)(
implicit
val toList: ToList[L, Lub],
val kt: Lub <:< KeyMapping[KeyType]
) {
val k: KeyType = null.asInstanceOf[KeyType]
}
(隐含不需要是val
s,但如果你在REPL中探索事物时它会有所帮助)
这断言,Lub
对应于KeyMapping[KeyType]
类型(例如,它是一个子类型或完全相同的类型),其中KeyType
是,然而,未知。同样,指定的约束只有一个有效的解决方案,而KeyType
参数被拉出为String
。
我不知道您计划如何实施k
,但您可能会发现拥有toList
实例可以帮助您这样做,因为它允许您现在调用mappings.toList
< / p>