我试图在 Scala 中获得最小形式的依赖类型。如果我有
class A[T <: Int]
val x: Int = 7
我可以
val a = new A[x.type]
现在有可能x
从它的单例中恢复x.type
吗?
或者,如果这不可能,是否可以以某种方式将稳定标识符与类型相关联,然后提取它?
我试图在 Scala 中获得最小形式的依赖类型。如果我有
class A[T <: Int]
val x: Int = 7
我可以
val a = new A[x.type]
现在有可能x
从它的单例中恢复x.type
吗?
或者,如果这不可能,是否可以以某种方式将稳定标识符与类型相关联,然后提取它?
不,由于 JVM 类型擦除,您无法x
从中恢复。x.type
例如,这将如何实现?
def f[A]: A = ???
f[x.type]
在 JVM 字节码级别,没有办法f
找到x: A
给定的值,A = x.type
因为它没有任何东西可以使用:所有类型参数在运行时都会丢失,无论如何,该值在的参数堆栈x
上不可用。f
出于同样的原因,要获得一个类型的稳定 ID,您必须将其具体化为一个Manifest
值。但是当我尝试时,我得到了一个奇怪的结果,
def f[A : Manifest] = implicitly[Manifest[A]]
val x = "hi"
val y = "ho"
println(f[x.type]) // hi.type
println(f[y.type]) // ho.type
f[x.type] == f[y.type] // true !?
我不确定为什么这两种类型的清单是相等的——它们甚至有不同的toString
表示。这可能是Scala错误吗?更新:根据ScalaDoc,类型关系运算符 <:< 和 =:= 应仅视为近似值,因为类型一致性的许多方面尚未在清单中充分表示。
总而言之,将类型信息具体化为运行时值不会在 JVM 上自动发生。ScalaManifest
应该可以填补这个空白,但我想它不适用于依赖类型。
要回答您的第二个问题,“将稳定的标识符与类型相关联”,一种方法是使用类型类。假设我想将字符串描述与类型相关联,我可以这样做:
trait Tag[A] {
val desc : String
}
implicit object StringTag extends Tag[String] {
val desc = "character string"
}
implicit object IntTag extends Tag[Int] {
val desc = "32-bit integer"
}
现在,要恢复此类标签,请输入隐式魔法:
def printTag[T : Tag] {
val tag = implicitly[Tag[T]]
println("Type is described as : " + tag.desc)
}
例如:
printTag[String] // prints "Type is described as : character string"
printTag[Double] // compile-time error: no implicit value found of type Tag[Double]
您甚至可以根据需要使用隐式函数生成标签。例如:
implicit def liftTagToList[T : Tag] = new Tag[List[T]] {
val underlying = implicitly[Tag[T]].desc
val desc = "list of " + underlying + "s"
}
我现在可以执行以下操作:
// prints "Type is described as : list of character strings"
printTag[List[String]]
乃至:
// prints "Type is described as : list of list of character stringss"
printTag[List[List[String]]]
请原谅复数。