2013-08-02 4 views
5

Почему эта функция не компилируется?Intersect Scala с набором подтипов

case class MyType(n: Int) 
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    (s1 & s2) 

Я получаю следующее сообщение об ошибке:

error: type mismatch; found : Set[_$1] where type _$1 <: MyType required: scala.collection.GenSet[MyType] Note: _$1 <: MyType, but trait GenSet is invariant in type A. You may wish to investigate a wildcard type such as _ <: MyType . (SLS 3.2.10) (w & r)

Есть простой способ "продвигать" второй аргумент к типу Set [MyType] без использования asInstanceOf?

ответ

2

A Set не является ковариантным по параметру своего типа.

Так простое решение для преобразования List (который ковариантен):

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    s1.toList.intersect(s2.toList).toSet 
3

Это потому, что Set определяется как Set[A]. Это in-variant и не ковариант.

& определяется как

def &(that: GenSet[A]): Set[A] 

Он ожидает и аргумент типа Set[A]. Но вместо этого вы предоставляете Set[_ <: MyType].

Set[_ <: Mytype] является со-вариантом до Set[MyType]. Но, как говорится в заявлении, аргумент должен быть в-вариантах, то есть Set[MyType], следовательно, ошибка.

PS: Вы можете думать о ковариации как преобразовании типов от узкого к более широкому. Например: если Dog распространяет Animal, и если вы делаете Animal a = new Dog(), у вас есть собака (узкое) преобразование в Animal (более широкое). Выше этого ожидает инвариантный тип. т. е. если он ожидает Animal, вы можете предоставить только Animal. Другим примером является java.util.ArrayList, который является in-variant.

+1

Спасибо за ваше объяснение. Тем не менее, теперь я не знаю, почему этот оператор typechecks правильно: Set (new Object()) & Set ("string") – tba

+0

@tba Это очень хорошее наблюдение. Я спросил его здесь: http://stackoverflow.com/questions/18029746/weird-behavior-of-function-in-set. благодаря – Jatin

2

Set инвариантно, однако есть удивительно простое решение:

def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) = 
    s2 filter s1 

Или, если кто-то хочет для получения лучшего вывода типа для типа результата:

def intersection[X <: MyType](s1: Set[MyType], s2: Set[X]): Set[X] = 
    s2 filter s1 

Здесь s1 используется как функция. Функции являются противоречивыми в аргументах, поэтому s1.apply типа (MyType) => Boolean допустим как (_ <: MyType) => Boolean.

Производительность такая же, как intersect, так как this filter that есть как intersect для Set.

Смежные вопросы