2014-05-01 15 views
5

Dựa trên câu trả lời cho this question, có vẻ như việc đặt "forSome" sau một thành phần của định nghĩa loại khác với đặt nó ở cuối toàn bộ điều. Ví dụ, có vẻ như có sự khác biệt giữa những điều sau đây:Điều gì quan trọng trong việc sắp xếp mệnh đề "forSome" trong cú pháp Generics Generale?

def one: Foo[U >: T] forSome {type U >: T} 

def one: Foo[U forSome {type U >: T}] 

Đặc tả ngôn ngữ Scala dường như không nói bất cứ điều gì về sự khác biệt, và tôi có thể tưởng tượng rằng việc di chuyển quantifiers ra bên ngoài sẽ làm cho có sự khác biệt . Nếu nó tạo ra sự khác biệt, tôi đã nghĩ nó sẽ được mô tả trong this answer, về cơ bản nói Set [X forSome {type X}] cho phép X thay đổi giữa các phần tử thiết lập, trong đó Set [X] forSome {type X} không phải. Tuy nhiên, điều này dường như không phải là toàn bộ câu chuyện và/hoặc là không đúng, bởi vì đây không biên dịch:

trait Bar { 
    def test: Set[X] forSome {type X} 
} 

def test(b: Bar) { 
    val set = b.test 
    val h = set.head 
    set.contains(h) 
} 

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

trait Bar { 
    def test: Set[X forSome {type X}] 
} 

def test(b: Bar) { 
    val set = b.test 
    val h = set.head 
    set.contains(h) 
} 

Dường như nếu Set [X] forSome {type X} tạo ra một kiểu trừu tượng riêng cho mỗi trang sử dụng trong lớp instantiated, trong đó Set [X forSome {type X}] chỉ tạo một kiểu và sử dụng nó cho toàn bộ lớp. Điều này trái ngược với những gì tôi mong đợi và có vẻ không phù hợp với câu trả lời ở trên.

+0

Điều này sẽ làm rõ tình huống ít nhất một chút http://stackoverflow.com/questions/21226004/what-is-and-when-to-use-scalas-forsome-keyword – Andrey

+0

@Andrey - Điều đó thật thú vị, đặc biệt bởi vì câu trả lời được chấp nhận cho câu hỏi ngụ ý rằng ngữ nghĩa ngược lại với những gì tôi nghĩ tôi đang thấy. –

+1

@Andrey - thực sự tôi sẽ đi xa hơn một chút và nói rằng câu trả lời được chấp nhận cho câu hỏi đó không hữu ích như một câu trả lời cho câu hỏi này và có thể không đúng. Xem ví dụ sửa đổi của tôi ở trên. –

Trả lời

4

Một vài quan sát để bắt đầu với: X forSome { type X } chỉ là một cách ưa thích để viết Any —nó là một kiểu mà chúng tôi không biết gì, vì vậy nó phải ở trên cùng của phân cấp loại. Nếu bạn không tin tôi, hãy yêu cầu trình biên dịch:

scala> implicitly[Any =:= X forSome { type X }] 
res0: =:=[Any, _] = <function1> 

Đúng vậy, nó đồng ý.

Relatedly, sau đây sẽ không biên dịch:

scala> val xs: Set[X forSome { type X }] = Set[Int](1, 2, 3) 
<console>:7: error: type mismatch; 
found : scala.collection.immutable.Set[Int] 
required: Set[X forSome { type X }] 
Note: Int <: X forSome { type X }, but trait Set is invariant in type A. 

Mà không phải là đáng ngạc nhiên cho những gì chúng ta vừa học được. Set là bất biến trong thông số loại của nó, do đó, Set[Int] không phải là Set[X forSome { type X }] (ví dụ: Set[Any]).

Với tất cả điều này, cũng không quá ngạc nhiên khi phương thức biên dịch test thứ hai. Khi chúng tôi đứng đầu số b.test, chúng tôi nhận được X forSome { type X } (ví dụ: Any) và chúng tôi cần X forSome { type X } (ví dụ: Any) cho b.test.contains.

Vì vậy, bây giờ cho Bar đầu tiên. Hãy xem xét những điều sau đây:

scala> val xs: Set[X] forSome { type X } = Set[Int](1, 2, 3) 
xs: Set[_] = Set(1, 2, 3) 

Ở đây chúng ta đã nói xs là một tập hợp của một số loại hình cụ thể X, nhưng chúng tôi ngay lập tức sẽ quên tất cả mọi thứ về X. Lưu ý rằng không giống như định nghĩa xs ở trên, điều này không biên dịch, vì chúng tôi không nói rằng xs là một tập hợp bất kỳ thứ gì, chỉ là một tập hợp một số loại cụ thể mà chúng tôi không biết (hay đúng hơn là trình biên dịch không biết).

Điều này có nghĩa là hoàn toàn không thể a sẽ thực hiện biên dịch xs.contains(a).Chúng ta hãy thử một rõ ràng một:

scala> xs.contains(1) 
<console>:9: error: type mismatch; 
found : Int(1) 
required: X 
       xs.contains(1) 
         ^

Thông báo lỗi ở đây là thú vị- chúng tôi biết rằng X thực sự là Int, nhưng trình biên dịch không, vì chúng ta một cách rõ ràng hỏi nó để quên rằng thực tế với forSome { type X }. Bạn có thể thấy một thông báo tương tự thú vị bằng cách viết lại phương pháp test của bạn cho Bar đầu tiên như sau:

def test(b: Bar) = b.test.contains(b.test.head) 

này cũng sẽ không biên dịch, với thông báo sau:

found : (some other)X(in method test) where type (some other)X(in method test) 
required: X(in method test) where type X(in method test) 
     def test(b: Bar) = b.test.contains(b.test.head) 
              ^

Đó là, thậm chí mặc dù chúng tôi chỉ cần rút ra rằng b.test.head trong số b.test, chúng tôi vẫn không thể áp dụng b.test.contains cho nó. Chúng tôi đã nói với trình biên dịch rằng điều duy nhất nó biết về loại mặt hàng của b.test là nó tồn tại, do đó, nó sẽ không theo dõi thực tế là b.test.head là loại điều mà chúng ta sẽ có thể áp dụng b.test.contains đến.

+0

Cảm ơn bạn, điều đó có ý nghĩa. –

Các vấn đề liên quan