2009-11-12 132 views
26

從另一個問題,我問繼,Scala 2.8 breakout,我想了解更多的關於Scala的方法TraversableLike[A].map其簽名如下:斯卡拉2.8 CanBuildFrom

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That 

注意的幾件事情有關此方法:

  • 它需要一個函數將遍歷中的每個A轉換爲B
  • 它返回That並採用CanBuildFrom[Repr, B, That]類型的隱式參數。

我可以調用這個如下:

> val s: Set[Int] = List("Paris", "London").map(_.length) 
s: Set[Int] Set(5,6) 

什麼我不能很好地領會是怎樣的事實That勢必B(即,它是B的部分集合)正在被編譯器強制執行。該類型的參數看起來是獨立的上方和性狀CanBuildFrom本身的簽名的簽名:

trait CanBuildFrom[-From, -Elem, +To] 

如何Scala編譯器確保That不能被迫到一些東西,沒有意義?

> val s: Set[String] = List("Paris", "London").map(_.length) //will not compile 

編譯器如何決定什麼隱含CanBuildFrom對象範圍的電話嗎?

+0

這裏是後一個相當不錯的解釋http://blog.bruchez.name/2012/08/getting-to-know-canbuildfrom-without-phd.html – 2012-08-23 21:33:26

+0

爲了記錄在案,這種用法有概念名稱:返回類型多態。 – lcn 2015-03-07 20:18:45

回答

29

請注意,map的第二個參數是一個隱式參數。有必須是一個隱含的範圍與適當的類型,否則,你必須通過這樣的說法。

在你的榜樣,That必須Set[String],B必須IntRepr必須List[String]。因此,對於編譯你需要的範圍如下隱含對象:

implicit object X: CanBuildFrom[List[String], Int, Set[String]] 

有在範圍上沒有這樣的事情。此外,breakOut不能提供它,因爲它本身需要一個隱式CanBuildFrom,其第一種類型可以是任何類別(反對後裔Nothing),但受其他類型限制。

看看,例如,在CanBuildFrom工廠從List同伴對象:

implicit def canBuildFrom [A] : CanBuildFrom[List, A, List[A]] 

因爲它通過A結合第二個和第三個參數,有問題的隱將無法正常工作。

那麼,如何知道在哪裏尋找,關於這種含義?首先,Scala確實會將一些東西導入到所有示波器中。現在,我可以回憶以下進口:

import scala.package._ // Package object 
import scala.Predef._ // Object 
// import scala.LowPriorityImplicits, class inherited by Predef 
import scala.runtime._ // Package 

既然大家都在關注implicits,請注意,當你從包中導入的東西,唯一可能的implicits是單身。另一方面,當你從對象(單例)導入東西時,你可以有隱含的定義,值和單例。

現在,PredefLowPriorityImplicits中有CanBuildFrom的含義,它們與字符串有關。它們使我們能夠編寫"this is a string" map (_.toInt)

因此,除了這些自動導入,以及您製作的顯式導入之外,還有哪些地方可以隱式地找到?一個地方:應用該方法的實例的伴隨對象。

我說同伴對象s,這是複數形式,因爲所討論的實例的類繼承的所有特徵和類的伴隨對象可能包含相關的含義。我不確定實例本身是否可能包含隱式。說實話,我現在不能複製這個,所以我肯定在這裏犯了某種錯誤。

無論如何,請查看伴侶對象。

+0

丹尼爾 - 我如何知道在我的代碼中給定點處隱式對象的範圍?我意識到這就是問題歸結到的問題。它在哪裏指定?另外,這個問題與'breakOut'無關。 – 2009-11-12 13:17:15

+0

除了對象scala.Predef中的隱式轉換之外,您必須在相同或封閉範圍中定義隱式,否則您必須顯式導入該隱式。 – 2009-11-12 15:33:00

+0

「,當你從軟件包中導入東西時,唯一可能的情況是單例」對於Scala 2.8軟件包對象,情況還是如此嗎?它們也可以包含隱式的defs和vals。 – 2011-02-15 14:21:05

0
object ArrayBuffer extends SeqFactory[ArrayBuffer] { 
    /** $genericCanBuildFromInfo */ 
    implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArrayBuffer[A]] = new GenericCanBuildFrom[A] 
    def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new ArrayBuffer[A] 
}