2011-01-29 84 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出版社。