Расширение коллекций Scala - PullRequest
3 голосов
/ 30 января 2011

Я хотел бы получить версию встроенной коллекции 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)]

Как я могу изменить класс, чтобы это работало?

Ответы [ 4 ]

7 голосов
/ 30 января 2011

Вы уверены, что вам действительно нужно расширить коллекцию 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, и ваши методы left и right будут доступны и в любых других реализациях (например, TreeSet).

Я думаю, что в большинстве случаев упаковка или составление + делегирование работают намного лучше, чем наследование (и вызывают меньше проблем).

4 голосов
/ 31 января 2011

Общий ответ на ваш вопрос слишком сложен для ответа здесь.Но это было написано на некоторых веб-страницах .

Тот же материал с большим контекстом также есть во 2-м издании нашей книги, Программирование на Scala, Artima Press.

4 голосов
/ 30 января 2011

Как сказал Кевин Райт , операция + вернет обратно HashSet. Тип class CanBuildFrom используется для создания новых коллекций во время таких операций, как map. Поэтому, если вы хотите, чтобы + вернул Tuple2Set вместо HashSet, вы должны реализовать CanBuildFrom и сделать его неявно доступным в объекте-компаньоне, например:

object Tuple2Set {
    implicit def canBuildFrom[T1, T2] = 
        new CanBuildFrom[Tuple2Set[T1, T2], (T1, T2), Tuple2Set[T1, T2]] {...}
}
0 голосов
/ 30 января 2011

Причина, по которой ваш пример не работает, заключается в том, что тип возвращаемого значения операции + равен HashSet, а не Tuple2Set.

Вам будет гораздо больше удачи, если использовать "шаблон «Прокачай мою библиотеку» вместо наследования.

...