2011-01-29 109 views
3

我想获得一个版本的Scala内置集合在特定泛型类型例如功能扩展的,扩展Scala集合

import scala.collection.immutable._ 
class Tuple2Set[T1,T2] extends HashSet[Tuple2[T1,T2]] { 
def left = map (_._1) 
def right = map (_._2) 
} 

然而,当我尝试用下面的测试中使用它

new Tuple2Set[String,String]() + (("x","y")) left 

我得到以下编译错误

error: value left is not a member of scala.collection.immutable.HashSet[(String, String)] 

我怎样才能改变CL屁股,这样的工作?

+0

我是新来的Scala,有人可以解释一下`map(_._ 1)`的意思吗?据我所知,例如`set.map(_ + 1)`会创建一个元素增加1的新集合,但是我无法得到'_._ 1'的作用。 – Nutel 2011-01-29 23:57:20

+1

@Vetal:`(_._ 1)`在这种情况下与'((x:Tuple [T1,T2])=> x._1)'和'_1'是'Tulple2'类中的字段相同,表示元组的第一个元素。 – tenshi 2011-01-30 00:05:23

+0

@Easy谢谢,如果我能我会接受你的回答 – Nutel 2011-01-30 00:08:45

回答

4

由于凯文·赖特说,+操作将返回HashSet。在类似map的操作中,类别类CanBuildFrom用于构建新的集合。所以,如果你想+返回Tuple2Set而不是HashSet你应该实现CanBuildFrom,并使其在同伴对象隐含可用这样的:

object Tuple2Set { 
    implicit def canBuildFrom[T1, T2] = 
     new CanBuildFrom[Tuple2Set[T1, T2], (T1, T2), Tuple2Set[T1, T2]] {...} 
} 
7

您确定您确实需要扩展Scala集合吗?为了让上面的代码工作,你可以这样做:

class Tuple2Set[T1,T2](set: Set[(T1, T2)]) { 
    def left = set map (_._1) 
    def right = set map (_._2) 
} 

implicit def toTuple2Set[T1, T2](set: Set[(T1, T2)]) = new Tuple2Set(set) 

Set[(String, String)]() + (("x","y")) left 

在这种情况下Tuple2Set只是任何其他Set实现包装。这意味着您不再局限于HashSet,您的方法leftright也可以在任何其他实现(如TreeSet)上使用。

我认为在大多数情况下,包装或组合+委托的工作比继承更好(并且导致更少的问题)。

0

你的例子不工作的原因是+操作的返回类型为HashSet,而不是一个Tuple2Set

使用“pimp my library”模式代替继承,你会有更多的运气。

4

一般回答你的问题是有点太涉及用于此处的响应。但它已被写入一些web pages

同样的材料和更多的上下文也出现在我们的书的第二版,斯卡拉编程,Artima出版社。