4

这个例子被简化了。

我有一组这样的类:

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

4

1 回答 1

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受 that 约束的有效实例L,其Lub类型被拉出。

Lub不过,这还不够,因为KeyMapping[String]您想要的只是String零件。与 shapeless 一样,解决方案是添加另一个隐式:

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]
}

(隐含不需要是vals,但是当你在 REPL 中探索事物时它会有所帮助)

这断言的是Lub对应于类型KeyMapping[KeyType] (例如,它是子类型或完全相同的类型),其中KeyType仍然是未知的。同样,对于指定的约束只有一个有效的解决方案,并且KeyType参数被提取为 is String

我不知道您打算如何实施k,但您可能会发现拥有该toList实例可以帮助您这样做,因为它允许您现在调用mappings.toList

于 2014-02-19T15:27:06.660 回答