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", "") } 
相关问题