考慮以下兩個表達式之間的區別:
Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)
和:
Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)
現在想想怎樣類型參數的valueOf
T
將在每種情況來推斷。在第一種情況下,我們得到了一個X
,我們知道它是Enum[X]
的一個子類型,並且我們都設置了。另一方面,在第二種情況下,T
必須是X forSome { type X <: Enum[X] }
,並且關鍵的是這種類型不是Enum[X forSome { type X <: Enum[X] }]
的子類型,所以我們還沒有滿足對T
的限制。
問題是,你的第二個例子相當於後者。
作爲一個註腳,如果Enum
在其類型參數進行了協變這會工作得很好。看看下面簡單的例子:
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] }] = ???
現在foo(x)
將編譯,但foo(y)
不會,就像在你的代碼。但有點改變Bar
:
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] }] = ???
現在他們都會編譯。我猜想這與我們對你的兩個例子具有如此強烈的直覺是相同的原因有關。
作爲另一個註腳(響應gzmo的comment below),考慮以下因素:
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]
讓我們假設X forSome { type X <: Foo[X] }
爲的Foo[X forSome { type X <: Foo[X] }]
(暫時忽略這樣一個事實:亞型後者甚至不是有效的類型)。然後我們就可以寫:
myFoo: Foo[X forSome { type X <: Foo[X] }]
但Foo
是不變的,所以如果我們有一些東西,這既是Foo[A]
和Foo[B]
的實例,那麼它必須是這樣的情況A =:= B
。但絕對不是這種情況,MyFoo =:= (X forSome { type X <: Foo[X] })
。不確定所有這一切都不那麼令人困惑,但是我確信編譯器知道它在這裏做了什麼。
我不明白爲什麼'X forSome {X型<:枚舉[X]}'不是'枚舉亞型[X forSome {X型<:枚舉[X]}]'(在我的腦海,'X <:Enum [X]'並且遞歸地應用相同的約束)。你可以解釋嗎?我們是否遇到F結合多態性的奇怪限制之一? – gzm0
@ gzm0:我的更新有幫助嗎? –