什么是Scala中的清单,什么时候需要它?

Jes*_*per 130 scala manifest

从Scala 2.7.2开始,有一些叫做ManifestJava类型擦除的解决方法.但是,如何Manifest确切地工作以及为什么/何时需要使用它?

Jorge Ortiz 的博客文章Manifests:Reified Types解释了其中的一些内容,但它没有解释如何将它与上下文界限一起使用.

那么ClassManifest,有什么区别Manifest

我有一些代码(一个更大的程序的一部分,不能轻易地包含在这里),它有关于类型擦除的一些警告; 我怀疑我可以通过使用清单解决这些问题,但我不确定如何解决.

Mit*_*ins 195

编译器知道有关类型的更多信息,而不是JVM运行时可以轻松表示的.清单是编译器在运行时向代码发送关于丢失的类型信息的跨维消息的一种方式.

这类似于Kleptonians如何在化石记录和人类的"垃圾"DNA中留下编码信息.由于光速和重力场的限制,它们无法直接通信.但是,如果你知道如何调整他们的信号,你可以从你无法想象的方式中受益,从决定午餐吃什么或玩多少乐透号码.

目前尚不清楚Manifest是否会在不了解更多细节的情况下使您所看到的错误受益.

清单的一个常见用法是根据集合的静态类型使代码的行为不同.例如,如果您希望以不同于List的其他类型处理List [String],该怎么办?

 def foo[T](x: List[T])(implicit m: Manifest[T]) = {
    if (m <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

  foo(List("one", "two")) // Hey, this list is full of strings
  foo(List(1, 2)) // Non-stringy list
  foo(List("one", 2)) // Non-stringy list
Run Code Online (Sandbox Code Playgroud)

基于反射的解决方案可能涉及检查列表中的每个元素.

上下文绑定似乎最适合在scala中使用类型类,Debasish Ghosh在这里对此进行了很好的解释:http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

上下文边界也可以使方法签名更具可读性.例如,可以使用上下文边界重写上述函数,如下所示:

  def foo[T: Manifest](x: List[T]) = {
    if (manifest[T] <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }
Run Code Online (Sandbox Code Playgroud)

  • 对用例进行了投票.希望我对左外场Kleptonian部分进行第二次投票. (17认同)
  • 啊哈,这是来自Scala编译器的秘密跨维消息...... ;-) (10认同)
  • @kirhgoff我以为他真的是指克莱普顿人.无论如何,这是一个很棒的模拟 - 需要阅读两次才能完全掌握.SO中的笑话很少见(尽管这不是一个笑话 - 严肃的解释). (3认同)

Von*_*onC 25

不是一个完整的答案,但对于之间的区别ManifestClassManifest,你可以找到一个例子斯卡拉2.8 Array:

唯一剩下的问题是如何实现通用数组创建.与Java不同,Scala允许实例创建new Array[T],其中T是类型参数.考虑到Java中不存在统一的数组表示,如何实现它?

执行此操作的唯一方法是需要额外的运行时信息来描述类型T.Scala 2.8有一个新的机制,称为Manifest.类型对象Manifest[T]提供有关类型的完整信息T.
Manifest值通常在隐式参数中传递; 并且编译器知道如何为静态已知类型构造它们T.

还存在一个较弱的命名形式ClassManifest,它可以通过只知道一个类型的顶级类来构造,而不必知道它的所有参数类型.
正是这种类型的运行时信息是数组创建所必需的.

例:

需要通过将ClassManifest[T]方法作为隐式参数传递给方法来提供此信息:

def  tabulate[T](len:Int,  f:Int=>T)(implicit m:ClassManifest[T]) =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 
Run Code Online (Sandbox Code Playgroud)

作为简写形式,可以在类型参数上使用上下文bound1 T,

(见这个问题的插图)

给予:

def  tabulate[T:    ClassManifest](len:Int,  f:Int=>T)  =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 
Run Code Online (Sandbox Code Playgroud)

当在类型上调用tabulate时Int,或者,或者String,或者List[T],Scala编译器可以创建一个类清单作为隐式参数传递给表格.


Mec*_*ail 23

Manifest旨在重新定义在JVM上运行类型擦除的泛型类型(不支持泛型).然而,他们有一些严重的问题:他们太简单了,并且无法完全支持Scala的类型系统.因此它们在Scala 2.10中被弃用,并被替换为TypeTags(这实际上是Scala编译器本身用于表示类型的内容,因此完全支持Scala类型).有关差异的更多详细信息,请参阅:

换一种说法

你什么时候需要它?

在2013-01-04之前,当Scala 2.10发布时.