我正在尝试在运行时恢复Scala中的依赖类型。我基本上想要归档一个类型保存映射,其中每个键都有一个关联的类型,但是Map的用户看不到所存储的键值对的所有类型信息(与真棒Shapeless Map不同)。 / p>
class Key[V] {
type Value = V
def ->(value: V) = Pair(this, value)
}
trait Pair {
val key: Key[_]
val value: key.Value
}
trait Map {
val pairs: Seq[Pair]
def get[V](key: Key[V]): Option[V] =
pairs.find(pair => pair.key eq key).map(_.value).asInstanceOf[Option[V]]
// ^ ^
// the runtime prove that pair.key.Value equals V |
// |
// 'Convince' the compile that I know what I do
}
用法:
val text = new Key[String]
val count = new Key[Int]
val map: Map = new Map { val pairs = text -> "Hello World!" :: Nil }
map.get(text) // Some(Hello World!), Type: Option[String]
map.get(count) // None, Type: Option[Int]
是否可以编写get
方法而不使用带asInstanceOf
的强制转换或隐式匹配未经检查的分支?
我尝试为成对编写unapply
,但遇到了同样的问题。
请注意,我省略了Pair-companion对象的定义。这是Gist中的一个正在运行的示例。
答案 0 :(得分:1)
请记住,JVM会在运行时删除泛型。所以任何依赖于泛型的东西,包括依赖类型,都只能在编译时发生 - 即在调用者中,因为任何给定的方法只能编译到一个运行时代码路径。唯一的选择是检查运行时类(直接或通过模式匹配),如你所说。 (如果沿着那条路走下去,Shapeless有一个类型安全的,类型类驱动的帮助器)
在没有类型问题的情况下,可能有一种聪明的方式来表达您的要求,但通常,类型信息必须对调用者可见或在运行时检查。
答案 1 :(得分:0)
解决您的类型问题的多种方法。首先定义问题的根源:
trait Map {
val pairs: Seq[Pair] // (1)
def get[V](key: Key[V]): Option[V] = // (2)
pairs.find(_.key eq key).map{_.value } // (3)
}
pairs
类型为Seq
的{{1}}(带有一些嵌入的未定义类型Pair
)key: Key[_]
类型为key
,预期结果类型为Key[V]
Option[V]
而不是预期Key[_]
返回类型并提取V 解决方案:您应该保证Key[V]
嵌入式pairs
与您返回的内容相同
可能的解决方案之一:
key