6

我有一個艱難的時間理解爲什麼Scala編譯器是不滿這個函數的定義:功能這一般需要一個類型並返回相同類型

def trimNonWordCharacters[T <: Iterable[String]](items: T): T = 
    items map { _.replaceAll("\\W", "") } 

這裏是REPL輸出:

scala> def trimNonWordCharacters[T <: Iterable[String]](items: T): T = 
    items map { _.replaceAll("\\W", "") } 
<console>:5: error: type mismatch; 
found : Iterable[java.lang.String] 
required: T 
     def trimNonWordCharacters[T <: Iterable[String]](items: T): T = items map { _.replaceAll("\\W", "") } 

目標是傳遞Iterable的任何實現並獲得相同類型的返回。這可能嗎?

+0

http://stackoverflow.com/questions/8235462/returning-original-collection-type-in​​-generic的重複方法 – 2012-04-04 22:24:34

+2

@LuigiPlinge這個問題不需要'CanBuildFrom',因爲'filter'不需要它。這個問題是非常相似的,這個問題的_title_肯定涵蓋了它,但是在這裏需要更多一點才能使它工作。 – 2012-04-05 12:32:37

回答

13

map方法上Iterable返回Iterable,所以即使TIterable一個子類,它是map方法將返回Iterable

爲了獲得更好的打字,你必須把它寫這樣的:

import scala.collection.IterableLike 
def trimNonWordCharacters[T <: Iterable[String]](items: T with IterableLike[String, T]): T = 
    items map { _.replaceAll("\\W", "") } 

不過,這也不行,因爲沒有信息,讓上T地圖生成另一個T。例如,將BitSet映射到String不會導致BitSet。所以我們需要別的東西:教導如何從T建立T,其中映射元素的類型爲String。就像這樣:

import scala.collection.IterableLike 
import scala.collection.generic.CanBuildFrom 
def trimNonWordCharacters[T <: Iterable[String]] 
         (items: T with IterableLike[String, T]) 
         (implicit cbf: CanBuildFrom[T, String, T]): T = 
    items map { _.replaceAll("\\W", "") } 
+0

非常感謝你 - 你的解釋是非常豐富的,現在我終於知道了一種使用'CanBuildFrom'(!)的方法 – 2012-04-04 22:04:21

0

[進入作爲回答,而不是評論,因爲評論代碼不正確地格式化]

@Daniel,感謝您的解釋,我也發現它有用。作爲可迭代從IterableLike派生,下面還似乎工作,而且是更爲簡潔:

import scala.collection.IterableLike 
import scala.collection.generic.CanBuildFrom 
def trimNonWordCharacters[T <: IterableLike[String, T]] 
(items: T) 
(implicit cbf: CanBuildFrom[T, String, T]): T = 
items map { _.replaceAll("\\W", "") }