2011-08-17 15 views
6

Chciałbym czerpać z niezmiennej mapy Scali. Jest ona definiowana jako takie:Czy można zmienić wariancję podstawowej klasy/cechy w Scali?

trait Map[A, +B] 

Niestety, moja realizacja musi być niezmienna w B. Próbowałem następujących, ale bez powodzenia:

def +(kv : (A, B)) : MyMap[A, B] = { ... } 

override def +[B1 >: B](kv : (A, B1)) : MyMap[A, B1] = 
    throw new IllegalArgumentException() 

Może jest jakaś sztuczka z @uncheckedVariance?

+1

Może chcesz użyć mapy elementu zamiast wyprowadzać? – Owen

+0

Ponadto, dlaczego musi być niezmienna? Pomyślałem (nie znam zbyt wiele Scali), że jedyną potrzebą niezmienności jest to, czy może to być źródło, czy zlew, ale mapy są niezmienne, więc nie może to być zlew. – Owen

+0

Chcę zaimplementować mapę dwukierunkową. Nic wielkiego, jeśli zaimplementuję Mapę i po prostu przekazuję obie mapy wewnętrzne, które definiują mapowanie do przodu i do tyłu, ale w tym przypadku potrzebuję niezmienności. –

Odpowiedz

1

Pozbycie się kowariancji jest oczywiście nieuzasadnione i nie jest dozwolone. Biorąc pod uwagę m: Map[A, String] i v : Any, możesz wykonać val mm : Map[A, Any] = m + v. Tak mówi definicja, a wszyscy operatorzy muszą za nią podążać. Twoja klasa może być niezmienna, ale musi implementować pełny interfejs kowariancyjny Map.

Teraz redefinicja +, aby rzucić błąd, to inna historia (jeszcze niezbyt dźwiękowa). Problem z nową metodą + polega na tym, że po usunięciu generics ma ona tę samą sygnaturę, co inna metoda +. Istnieje pewna sztuczka: dodaj niejawny parametr, aby mieć dwa parametry w podpisie, co odróżnia go od pierwszego.

def +(kv : (A,B))(implicit useless: A <:< A) : MyMap[A,B] 

(to naprawdę nie ma znaczenia, co ukryte parametr szukasz, tak długo, jak jeden został znaleziony. implicit useless: Ordering[String] działa tak samo dobrze)

Doing że masz zwykły problem z przeciążeniem . Jeśli dodasz B bez kompilatora wiedząc, że tak jest, zostanie wywołana metoda błędu. Lepiej byłoby wykonać tam test typu, aby instancje B były akceptowane niezależnie od tego. To wymagałoby otrzymania Manifestu [B] na twojej mapie.

3

Problem polega na tym, że jeśli otrzymasz niezmienną wersję z niezmiennej mapy, złamiesz bezpieczeństwo typu. Na przykład:

val dm = DiotMap(1 -> "abc") 
val m: Map[Int, Any] = dm 

Niniejsza deklaracja jest ważna, ponieważ Map jest kowariantna. Jeśli twoja kolekcja nie radzi sobie z kowariancją, co się stanie, gdy użyję m?

Powiązane problemy