Массивы Scala против векторов

Scala newb... Я запутался

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

"args" - это тип Array[String], но в scaladoc массив не имеет такого метода. mkString-это метод для вектора, но я не вижу никакой связи наследования между ними. Итак, почему мы можем использовать метод mkString для args?

3 ответов


Я не эксперт scala (далеко не так!) но я думаю, что ответ-неявные преобразования (см. scala.Predef) и WrappedArray.скала.

в частности, 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


расширение ответа Кевина и объяснение, почему это не возможно для 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 метод.

Итак, имея это в виду, вы можете понять, почему scaladoc на Array не могу сказать, какое неявное преобразование может применяться. Это может быть что угодно. На самом деле он полностью основан на том факте, что такого метода нет. Только компилятор будет знать, какой неявный он нашел на основе кода.

вы даже можете определить свое собственное неявное преобразование:

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 может привести вас к реализации mkString нажав F3 (вы окажетесь в TraversableOnce).


но Scaladoc мог бы по крайней мере сказать, что Predef (который является специальным, потому что он всегда находится в области) имеет неявное преобразование из массива. Это было бы полезно.