Scala newb ......我很困惑
object myApp extends App {
println("Echo" + (args mkString " "))
}
“args”是类型Array [String],但在scaladoc中,Array没有这样的方法。 mkString是Vector的一种方法,但我没有看到两者之间的任何继承链接。那么为什么我们可以在args上使用mkString方法呢?
答案 0 :(得分:17)
我不是scala专家(远非它!)但我认为答案是隐式转换(请参阅scala.Predef
)和WrappedArray.scala。
特别是,Predef具有以下隐式转换:
implicit def genericWrapArray [T] (xs: Array[T]): WrappedArray[T]
WrappedArray有一个mkString方法。当scala在Array上找不到mkString方法时,它会查找到类型的隐式转换。
http://www.scala-lang.org/api/current/scala/Predef $。HTML
http://www.scala-lang.org/api/current/scala/collection/mutable/WrappedArray.html
答案 1 :(得分:12)
扩展Kevin的答案,并解释为什么 scaladoc 不可能告诉你隐含的转换存在:隐式转换仅在你的代码无法编译时才会发挥作用。
您可以将其视为编译期间激活的类型错误的错误恢复机制。在这种情况下,Array[String]
没有mkString
方法。此代码无法编译,因为Array[T]
上不存在该方法。但在放弃之前,编译器会在范围内寻找隐式转换。
恰好Predef
在范围内带来了许多隐式转换,并且会在此处应用。
通过使用-Xprint:typer
标志进行编译,可以找出适用的隐式转换。在这种情况下,它将打印:
$ scalac -d classes -Xprint:typer A.scala
[[syntax trees at end of typer]]// Scala source: A.scala
package <empty> {
final object myApp extends java.lang.Object with App with ScalaObject {
def this(): object myApp = {
myApp.super.this();
()
};
scala.this.Predef.println("Echo ".+(scala.this.Predef.refArrayOps[String](myApp.this.args).mkString(" ")))
}
}
因此,您可以看到Predef.refArrayOps
实际上是使用的隐式转换。它会将您的数组转换为具有mkString
method的ArrayOps[String]
。
因此,考虑到这一点,您可以看到Array
的 scaladoc 无法告诉您隐式转换可能适用的原因。它可能是任何东西。事实上,它完全基于没有这种方法的事实。只有编译器才会知道它基于代码发现的隐式内容。
您甚至可以定义自己的隐式转换:
object myApp extends App {
implicit def myImplicit(arr:Array[String]) = new {
def mkString(s:String) = arr.length + s
}
println("Echo " + (args mkString(" ")))
}
会产生以下影响:
$ scala -cp classes myApp a b c
Echo 3
显然scaladoc无法证明这一点。请注意,Eclipse Scala插件可以通过按F3将您带到mkString
的实现(您将最终进入TraversableOnce
)。
答案 2 :(得分:2)
但Scaladoc至少可以说Predef(这是特殊的,因为它总是在范围内)具有从Array的隐式转换。那将是有用的。