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

发布于 2024-09-09 16:18:20 字数 553 浏览 5 评论 0 原文

从 Scala 2.7.2 开始,有一个名为 Manifest 的东西,它是 Java 类型擦除的解决方法。但是 Manifest 到底是如何工作的以及为什么/何时需要使用它?

博客文章清单:具体化类型< Jorge Ortiz 的 /em> 解释了其中的一些内容,但没有解释如何将其与 上下文边界

另外,ClassManifest是什么,和Manifest有什么区别?

我有一些代码(较大程序的一部分,不能轻易地将其包含在此处),其中有一些关于类型擦除的警告;我怀疑我可以通过使用清单来解决这些问题,但我不确定具体如何解决。

Since Scala 2.7.2 there is something called Manifest which is a workaround for Java's type erasure. But how does Manifest work exactly and why / when do you need to use it?

The blog post Manifests: Reified Types by Jorge Ortiz explains some of it, but it doesn't explain how to use it together with context bounds.

Also, what is ClassManifest, what's the difference with Manifest?

I have some code (part of a larger program, can't easily include it here) that has some warnings with regard to type erasure; I suspect I can solve these by using manifests, but I'm not sure exactly how.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

笨笨の傻瓜 2024-09-16 16:18:20

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

在不了解更多细节的情况下,尚不清楚清单是否有利于您所看到的错误。

清单的一种常见用途是让代码根据集合的静态类型表现不同。例如,如果您想将 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

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

上下文绑定似乎最适合在 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")
  }

The compiler knows more information about types than the JVM runtime can easily represent. A Manifest is a way for the compiler to send an inter-dimensional message to the code at runtime about the type information that was lost.

It isn't clear if a Manifest would benefit the errors you are seeing without knowing more detail.

One common use of Manifests is to have your code behave differently based on the static type of a collection. For example, what if you wanted to treat a List[String] differently from other types of a List:

 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

A reflection-based solution to this would probably involve inspecting each element of the list.

A context bound seems most suited to using type-classes in scala, and is well explained here by Debasish Ghosh:
http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Context bounds can also just make the method signatures more readable. For example, the above function could be re-written using context bounds like so:

  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")
  }
巷雨优美回忆 2024-09-16 16:18:20

清单旨在具体化经过类型擦除以在 JVM 上运行的泛型类型(JVM 不支持泛型)。然而,它们有一些严重的问题:它们过于简单化,并且无法完全支持 Scala 的类型系统。因此,它们在 Scala 2.10 中被弃用,并被 TypeTag 取代(这本质上是 Scala 编译器本身用来表示类型的内容,因此完全支持 Scala 类型)。有关差异的更多详细信息,请参阅:

换句话说

什么时候需要?

2013 年 1 月 4 日之前,Scala 2.10 发布时

A Manifest was intended to reify generic types that get type-erased to run on the JVM (which does not support generics). However, they had some serious issues: they were too simplistic, and were unable to fully support Scala's type system. They were thus deprecated in Scala 2.10, and are replaced with TypeTags (which are essentially what the Scala compiler itself uses to represent types, and therefore fully support Scala types). For more details on the difference, see:

In other words

when do you need it?

Before 2013-01-04, when Scala 2.10 was released.

浅唱ヾ落雨殇 2024-09-16 16:18:20

这不是一个完整的答案,但关于 ManifestClassManifest 之间的区别,您可以在 Scala 2.8 Array 论文

剩下的唯一问题是如何实现通用数组创建。与 Java 不同,Scala 允许创建实例 new Array[T],其中 T 是类型参数。鉴于 Java 中不存在统一的数组表示形式,如何实现这一点?

执行此操作的唯一方法是需要描述类型 T 的附加运行时信息。 Scala 2.8 为此提供了一个新机制,称为 ManifestManifest[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 
} 

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

(参见此SO 问题用于说明

,给予:

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 
} 

当对 IntStringList[T] 等类型调用 tabulate 时,Scala 编译器可以创建一个类清单作为隐式参数传递给制表。

Not a complete answer, but regarding the difference between Manifest and ClassManifest, you can find an example in the Scala 2.8 Array paper:

The only remaining question is how to implement generic array creation. Unlike Java, Scala allows an instance creation new Array[T] where T is a type parameter. How can this be implemented, given the fact that there does not exist a uniform array representation in Java?

The only way to do this is to require additional runtime information which describes the type T. Scala 2.8 has a new mechanism for this, which is called a Manifest. An object of type Manifest[T] provides complete information about the type T.
Manifest values are typically passed in implicit parameters; and the compiler knows how to construct them for statically known types T.

There exists also a weaker form named ClassManifest which can be constructed from knowing just the top-level class of a type, without necessarily knowing all its argument types.
It is this type of runtime information that’s required for array creation.

Example:

One needs to provide this information by passing a ClassManifest[T] into the
method as an implicit parameter:

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 
} 

As a shorthand form, a context bound1 can be used on the type parameter T instead,

(See this SO question for illustration)

, giving:

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 
} 

When calling tabulate on a type such as Int, or String, or List[T], the Scala compiler can create a class manifest to pass as implicit argument to tabulate.

心凉怎暖 2024-09-16 16:18:20

我们还检查 scala 源 (Manifest.scala) 中的 manifest,我们看到:

Manifest.scala:
def manifest[T](implicit m: Manifest[T])           = m

因此,对于以下示例代码:

def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
  if (m <:< manifest[String]) {
    "its a string"
  } else {
    "its not a string"
  }
}

我们可以看到manifest function 搜索隐式 m:Manifest[T] ,它满足您在我们的代码中提供的类型参数示例代码是 manifest[String]。因此,当您调用类似以下内容时:

if (m <:< manifest[String]) {

您正在检查您在函数中定义的当前隐式 m 是否为 manifest[String] 类型,并且作为 manifest< /code> 是一个 manifest[T] 类型的函数,它将搜索特定的 manifest[String] 并查找是否存在这样的隐式。

Let's also chck out manifest in scala sources (Manifest.scala), we see:

Manifest.scala:
def manifest[T](implicit m: Manifest[T])           = m

So with regards to following example code:

def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
  if (m <:< manifest[String]) {
    "its a string"
  } else {
    "its not a string"
  }
}

we can see that the manifest function searches for an implicit m: Manifest[T] which satisfies the type parameter you provide in our example code it was manifest[String]. So when you call something like:

if (m <:< manifest[String]) {

you are checking if the current implicit m which you defined in your function is of type manifest[String] and as the manifest is a function of type manifest[T] it would search for a specific manifest[String] and it would find if there is such an implicit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文