2013-08-23 111 views
8

Ít gây nhầm lẫn về các loại hiện có.Các loại ngoại lệ trong Scala

này làm việc cho tôi:

def valueOf(c: Class[_], name: String) { 
    type C = Class[T] forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[C], name) 
} 

nhưng điều này không:

def valueOf(c: Class[_], name: String) { 
    type T = T forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[Class[T]], name) 
} 

Trong tâm trí của tôi cả hai biểu thức tương đương với:

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name) 

Nhưng Scala nói rằng nó ở tâm trí của tôi chỉ:

inferred type arguments [T] do not conform to method valueOf's type parameter bounds [T <: Enum[T]] 
     Enum.valueOf(c.asInstanceOf[Class[T]], name) 
      ^

Trả lời

5

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] } 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]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.

+0

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

+0

@ gzm0: Bản cập nhật của tôi có trợ giúp không? –