Hãy xem xét sự khác biệt giữa hai biểu thức sau:
Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)
Và:
Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)
Bây giờ nghĩ về cách thức tham số kiểu T
của valueOf
sẽ được suy ra trong mỗi trường hợp này. Trong trường hợp đầu tiên, chúng tôi có một số X
mà chúng tôi biết là một loại phụ của Enum[X]
và chúng tôi đã hoàn tất. Mặt khác, trong trường hợp thứ hai, T
sẽ phải là X forSome { type X <: Enum[X] }
và chủ yếu là loại này không phải là loại phụ của Enum[X forSome { type X <: Enum[X] }]
, vì vậy, chúng tôi chưa thỏa mãn ràng buộc trên T
.
Vấn đề là ví dụ thứ hai của bạn tương đương với ví dụ thứ hai.
Dưới dạng chú thích, điều này sẽ hoạt động tốt nếu Enum
có cùng giá trị trong thông số loại của nó. Lấy ví dụ đơn giản sau:
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] }] = ???
Bây giờ foo(x)
sẽ biên dịch, nhưng foo(y)
sẽ không, cũng giống như trong mã của bạn. Nhưng thay đổi Bar
một chút:
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] }] = ???
Bây giờ cả hai đều sẽ biên dịch. Tôi đoán rằng điều này có liên quan đến lý do chúng tôi có những trực giác mạnh mẽ như vậy về hai ví dụ của bạn là tương đương.
Như một chú thích (để đáp ứng với gzmo 's comment below), hãy xem xét những điều sau đây:
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]
Giả sử rằng X forSome { type X <: Foo[X] }
là một subtype của Foo[X forSome { type X <: Foo[X] }]
(bỏ qua trong một khoảnh khắc thực tế là sau này không phải là một loại hợp lệ). Sau đó, chúng tôi có thể viết như sau:
myFoo: Foo[X forSome { type X <: Foo[X] }]
Nhưng Foo
là bất biến, vì vậy nếu chúng ta có một số điều mà là một thể hiện của cả hai Foo[A]
và Foo[B]
, sau đó nó phải là trường hợp đó A =:= B
. Nhưng nó chắc chắn không phải là trường hợp MyFoo =:= (X forSome { type X <: Foo[X] })
.Không chắc chắn tất cả điều đó là ít gây nhầm lẫn, nhưng đó là cách tôi thuyết phục bản thân mình rằng trình biên dịch biết những gì nó đang làm ở đây.
Tôi không hiểu tại sao 'X forSome {type X <: Enum [X]}' không phải là kiểu con của 'Enum [X forSome {type X <: Enum [X]}]' (trong tâm trí của tôi, 'X <: Enum [X] 'và các ràng buộc tương tự áp dụng đệ quy). Bạn có thể giải thích? Chúng ta có đang chạy vào một trong những hạn chế kỳ lạ của tính đa hình liên kết F không? – gzm0
@ gzm0: Bản cập nhật của tôi có trợ giúp không? –