Scala 数组 vs 向量

9

Scala新手指南:我很困惑

object myApp extends App {
  println("Echo" + (args mkString " "))
}

"

\"args\"是一个Array[String]类型,但在scaladoc中,Array没有这样的方法。mkString是一个Vector的方法,但我没有看到两者之间的任何继承链接。那么为什么我们可以在args上使用mkString方法?

"
3个回答

17

我不是scala专家(离得很远!),但我认为答案是隐式转换(请参见scala.Predef)和WrappedArray.scala。

特别地,Predef有以下隐式转换:

implicit def genericWrapArray [T] (xs: Array[T]): WrappedArray[T] 

而 WrappedArray 有一个 mkString 方法。当 Scala 在数组上找不到 mkString 方法时,它会寻找一个隐式转换到具有该方法的类型。

http://www.scala-lang.org/api/current/scala/Predef$.html

http://www.scala-lang.org/api/current/scala/collection/mutable/WrappedArray.html


2
谢谢,我之前没有听说过隐式转换。WrappedArray和Vector都从TraversableOnce特质中继承了mkString方法。如果scaladoc在类的定义中告诉你存在哪些隐式def可能会很有用? - Luigi Plinge

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实际上是使用的隐式转换。它将数组转换为ArrayOps[String],该类型确实具有mkString方法
因此,您现在可以明白为什么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(你会进入TraversableOnce)来将你带到mkString的实现。


2

但是Scaladoc至少可以说Predef(因为它总是在范围内)有一个从Array进行隐式转换的特殊功能。那将会很有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接