Scala Arrays vs Vectors
Scala newb...开发者_如何学运维 I'm confused
object myApp extends App {
println("Echo" + (args mkString " "))
}
"args" is type Array[String], but in the scaladoc, Array has no such method. mkString is a method for Vector, but I don't see any inheritance link between the two. So why can we use the mkString method on args?
I'm not a scala expert (far from it!) but I think the answer is implicit conversions (see scala.Predef
) and WrappedArray.scala.
In particular, Predef has the following implicit conversion:
implicit def genericWrapArray [T] (xs: Array[T]): WrappedArray[T]
And WrappedArray has a mkString method. When scala can't find a mkString method on Array, it looks for an implicit conversion to a type that does.
http://www.scala-lang.org/api/current/scala/Predef$.html
http://www.scala-lang.org/api/current/scala/collection/mutable/WrappedArray.html
Expanding on Kevin's answer and explaining why it's not possibly for scaladoc to tell you what implicit conversion exists: implicit conversions only come into play when your code would not compile otherwise.
You can see it as an error recovery mechanism for type errors that is activated during compilation. In this case, Array[String]
does not have a mkString
method. This code would not compile, because that method does not exists on Array[T]
. But before giving up the compiler will look for an implicit conversion in scope.
It happens that Predef
brings a number of implicit conversions in scope and one that will apply here.
Finding out which implicit conversion applies can be done by compiling with the -Xprint:typer
flag. In this case it would print:
$ 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(" ")))
}
}
So you can see that Predef.refArrayOps
is in fact the implicit conversion used. It converts your array into a ArrayOps[String]
which does have a mkString
method.
So with that in mind you can see why scaladoc for Array
cannot tell you what implicit conversion could apply. It could be anything. It is in fact wholly based on the fact that there is no such method. Only the compiler will know what implicit it found based on the code.
You can even define your own implicit conversion:
object myApp extends App {
implicit def myImplicit(arr:Array[String]) = new {
def mkString(s:String) = arr.length + s
}
println("Echo " + (args mkString(" ")))
}
Which would have the following effect:
$ scala -cp classes myApp a b c
Echo 3
Obviously scaladoc won't be able to show that. Note that the Eclipse Scala plug in can bring you to the implementation of mkString
by pressing F3 (you'll end up in TraversableOnce
).
But Scaladoc could at least say that Predef (which is special because it's always in scope) has an implicit conversion from Array. That would be useful.
精彩评论