2014-10-07 31 views
10

Ai đó có thể giải thích lý do tại sao những điều sau không hoạt động. Bằng cách nào đó làm mất một số thông tin cho suy luận kiểu khi tôi làm toSet, nhưng tôi không hiểu tại sao.toSet và nhập suy luận

scala> case class Foo(id: Int, name: String) 
defined class Foo 

scala> val ids = List(1,2,3) 
ids: List[Int] = List(1, 2, 3) 

scala> ids.toSet.map(Foo(_, "bar")) 
<console>:11: error: missing parameter type for expanded function ((x$1) => Foo(x$1, "bar")) 
       ids.toSet.map(Foo(_, "bar")) 
           ^

scala> ids.map(Foo(_, "bar")).toSet 
res1: scala.collection.immutable.Set[Foo] = Set(Foo(1,bar), Foo(2,bar), Foo(3,bar)) 
+1

Dường như trình biên dịch cần một số trợ giúp tạo kiểu rõ ràng, 'ids.toSet.map (Foo (_: Int," bar "))' – jarandaf

+0

Có, nhưng tại sao anh ta không biên dịch cần thông tin khi tôi làm toSet sau bản đồ ?? – regexp

+1

Nhạy cảm, công trình này, 'val a = ids.toSet; a.map (Foo (_, "bar")) ' – elm

Trả lời

6

Giả sử tôi đã có những điều sau đây:

trait Pet { 
    def name: String 
} 

case class Dog(name: String) extends Pet 

val someDogs: List[Dog] = List(Dog("Fido"), Dog("Rover"), Dog("Sam")) 

Set không được hiệp biến trong tham số kiểu của nó, nhưng List là. Điều này có nghĩa là nếu tôi có số List[Dog] Tôi cũng có một số List[Pet], nhưng Set[Dog]không phải a Set[Pet]. Để thuận tiện, Scala cho phép bạn upcast trong quá trình chuyển đổi từ List (hoặc các loại bộ sưu tập khác) thành một số Set bằng cách cung cấp thông số loại rõ ràng trên toSet. Khi bạn viết val a = ids.toSet; a.map(...), thông số loại này được suy ra và bạn ổn. Khi bạn viết ids.toSet.map(...), mặt khác, nó không suy ra, và bạn không may mắn.

Điều này cho phép những điều sau đây để làm việc:

scala> val twoPetSet: Set[Pet] = someDogs.toSet.take(2) 
twoPetSet: Set[Pet] = Set(Dog(Fido), Dog(Rover)) 

Trong khi điều này không:

scala> val allDogSet: Set[Dog] = someDogs.toSet 
allDogSet: Set[Dog] = Set(Dog(Fido), Dog(Rover), Dog(Sam)) 

scala> val twoPetSet: Set[Pet] = allDogSet.take(2) 
<console>:14: error: type mismatch; 
found : scala.collection.immutable.Set[Dog] 
required: Set[Pet] 
Note: Dog <: Pet, but trait Set is invariant in type A. 
You may wish to investigate a wildcard type such as `_ <: Pet`. (SLS 3.2.10) 
     val twoPetSet: Set[Pet] = allDogSet.take(2) 
              ^

Đây có phải là giá trị sự nhầm lẫn? Tôi không biết. Nhưng nó rất hợp lý, và đó là quyết định mà các nhà thiết kế API Bộ sưu tập đã thực hiện cho toSet, vì vậy chúng tôi bị mắc kẹt với nó.

+0

Một điều khó hiểu về điều này là không có khả năng suy ra một loại cho 'toSet' được trình bày bởi trình biên dịch là không có khả năng suy ra một kiểu cho' Foo (_, "bar") '. Các hội nghị truyền hình dường như làm việc trong hai hướng: 'ids.toSet [Int] .map (Foo (_," bar "))' không phàn nàn, và cũng không 'ids.toSet.map (Foo (_: Int, "bar")) '. –

+0

@Joe: Vấn đề là 'map' cần phải biết loại đối số của đối số của nó. Nếu loại thiết lập mà nó đang được gọi là chưa biết hoặc chưa được suy ra, bạn phải cung cấp loại đó một cách rõ ràng. –