2011-05-25 81 views
8

斯卡拉福利局...我很困惑Scala的陣列VS載體

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

「ARGS」 的類型是陣列[字符串],但在scaladoc,陣列有沒有這樣的方法。 mkString是Vector的一種方法,但是我沒有看到兩者之間的任何繼承關係。那麼爲什麼我們可以在參數上使用mkString方法呢?

回答

16

我不是一個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

+2

謝謝,我沒有隱式轉換的負責人。 WrappedArray和Vector都從它們共享的T​​raversableOnce特徵中獲取mkString方法。如果scaladoc在類的定義中告訴你隱含的defs存在,可能會有用嗎? – 2011-05-25 23:14:29

12

擴大對凱文的回答,並解釋爲什麼它是不可能的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 method

因此,考慮到這一點,您可以看到爲什麼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插件可以通過按F3(最終會在TraversableOnce中)實現mkString

+0

感謝您的詳細解釋:) – 2011-05-26 04:38:35

2

但是Scaladoc至少可以說Predef(這很特別,因爲它總是在範圍內)具有從Array的隱式轉換。這將是有益的。