Rozważmy różnicę między dwóch poniższych wyrażeń:
Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)
oraz:
Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)
Teraz pomyśl o tym, jak parametr typu T
od valueOf
będzie wnioskować w każdym z tych przypadków. W pierwszym przypadku mamy X
, który, jak wiemy, jest podtypem Enum[X]
, a my wszyscy jesteśmy ustawieni. W drugim przypadku, z drugiej strony, T
musiałby być X forSome { type X <: Enum[X] }
, a co najważniejsze, ten typ nie jest podtypem Enum[X forSome { type X <: Enum[X] }]
, więc nie spełniamy ograniczenia na T
.
Problem polega na tym, że twój drugi przykład jest równoważny temu drugiemu.
jako przypis, to będzie działać dobrze, jeśli Enum
zostały kowariantna w jego parametr typu. Weźmy następujący uproszczony przykład:
trait Foo[A]
trait Bar[A]
def foo[A <: Bar[A]](f: Foo[A]) = f
def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???
Teraz foo(x)
skompiluje, ale foo(y)
nie będzie, tak jak w kodzie. Ale zmień nieco: Bar
bit:
trait Foo[A]
trait Bar[+A]
def foo[A <: Bar[A]](f: Foo[A]) = f
def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???
Teraz obie się skompilują. Sądzę, że ma to coś wspólnego z tym, że mamy tak silną intuicję, że twoje dwa przykłady są równoważne.
W innym przypisie (w odpowiedzi na gzmo „s comment below), należy rozważyć następujące kwestie:
scala> trait Foo[A <: Foo[A]]
defined trait Foo
scala> class MyFoo extends Foo[MyFoo]
defined class MyFoo
scala> val myFoo = new MyFoo
myFoo: MyFoo = [email protected]
scala> myFoo: (X forSome { type X <: Foo[X] })
res0: X forSome { type X <: Foo[X] } = [email protected]
scala> myFoo: Foo[MyFoo]
res1: Foo[MyFoo] = [email protected]
Załóżmy, że X forSome { type X <: Foo[X] }
były podtypem Foo[X forSome { type X <: Foo[X] }]
(pomijając na chwilę fakt, że ten ostatni nie jest nawet poprawnym typem). Wtedy będziemy mogli napisać następujące:
myFoo: Foo[X forSome { type X <: Foo[X] }]
Ale Foo
jest niezmienna, więc jeśli mamy jakąś rzecz, która jest instancją zarówno Foo[A]
i Foo[B]
, to musi być tak, że A =:= B
. Ale na pewno nie jest tak, że MyFoo =:= (X forSome { type X <: Foo[X] })
.Nie jestem pewien, czy to wszystko jest mniej kłopotliwe, ale przekonałem się, że kompilator wie, co tu robi.
Nie rozumiem, dlaczego 'X forSome {type X <: Enum [X]}' nie jest podtypem 'Enum [X forSome {type X <: Enum [X]}]' (w mojej głowie, 'X <: Enum [X] 'i te same ograniczenia mają zastosowanie rekursywnie). Możesz wytłumaczyć? Czy napotykamy jedno z dziwnych ograniczeń polimorfizmu związanego z F? – gzm0
@ gzm0: Czy moja aktualizacja pomaga? –