找不到scala.reflect.ClassManifest [T]类型的证据参数的隐式值

dmi*_*try 19 types scala

似乎我不明白一些重要的事情,也许是关于擦除(该死的).

我有一个方法,我想创建一个大小的数组,其中n包含以下值gen:

def testArray[T](n: Int, gen: =>T) {
  val arr = Array.fill(n)(gen)
  ...
}
Run Code Online (Sandbox Code Playgroud)

并使用它,例如:

testArray(10, util.Random.nextInt(10))
Run Code Online (Sandbox Code Playgroud)

但我得到错误:

scala: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
val arr = Array.fill(n)(gen)
                       ^
Run Code Online (Sandbox Code Playgroud)

请解释一下我做错了什么,为什么会出现这个错误,以及它使哪种代码变得不可能?

dre*_*xin 14

那是因为在编译时不知道testArray具体类型T.您的签名必须看起来像def testArray[T : ClassManifest](n: Int, gen: =>T),这将为ClassManifest[T]您的方法添加一个类型的隐式参数,它会自动传递给调用,testArray然后进一步传递给Array.fill调用.这被称为a context bound.


EEC*_*LOR 5

Array.fill方法具有以下签名:

def fill[T](n: Int)(elem: => T)(implicit arg0: ClassManifest[T]): Array[T]
Run Code Online (Sandbox Code Playgroud)

为了获得一个实例,ClassManifest[T]你需要知道具体的类型。AClassManifest可以这样获得:

implicitly[ClassManifest[String]]
Run Code Online (Sandbox Code Playgroud)

AClassManifest隐式可用于每个具体类型。

对于任何implicit错误,您可以使用 type 参数将所需的隐式添加到方法中:

def wrap[T](n:Int)(elem: => T)(implicit c:ClassManifest[T], o:Ordering[T])
Run Code Online (Sandbox Code Playgroud)

如果您没有自己介绍ClassManifestOrdering,图书馆的作者(很可能)为您提供了合理的默认值。

如果您要调用该wrap方法:

wrap(2)(3)
Run Code Online (Sandbox Code Playgroud)

它是这样展开的:

wrap[Int](2)(3)(implicitly[ClassManifest[Int]], implicitly[Ordering[Int]])
Run Code Online (Sandbox Code Playgroud)

如果您Person在此处引入了自定义类,则会因为找不到Ordering[Person]. 图书馆的作者不可能知道如何订购Person。你可以这样解决:

class Person

implicit val o = new Ordering[Person] { // implement required methods }

wrap(2)(new Person)
Run Code Online (Sandbox Code Playgroud)

Scala 编译器在不同的范围内查找隐式,Ordering通常不会像这样指定。我建议您在互联网上查找隐式分辨率以了解更多信息。