2012-10-28 26 views
8

này lỗi sau tôi:lỗi: biểu hiện đa hình với các đối số mặc định

trait Foo[A] 
class Bar[A](set: Set[Foo[A]] = Set.empty) 

này mang lại

<console>:8: error: polymorphic expression cannot be instantiated to expected type; 
found : [A]scala.collection.immutable.Set[A] 
required: Set[Foo[?]] 
     class Bar[A](set: Set[Foo[A]] = Set.empty) 
             ^

Nó là khá khó chịu mà tôi phải lặp lại các tham số gõ vào Set.empty. Tại sao suy luận kiểu không thành công với đối số mặc định này? Các công trình sau đây:

class Bar[A](set: Set[Foo[A]] = { Set.empty: Set[Foo[A]] }) 

Xin lưu ý rằng điều này không có gì để làm với Set đặc biệt:

case class Hallo[A]() 
class Bar[A](hallo: Hallo[A] = Hallo.apply) // nope 

Kỳ lạ thay không chỉ hoạt động này:

class Bar[A](hallo: Hallo[A] = Hallo.apply[A]) 

... nhưng cũng có điều này:

class Bar[A](hallo: Hallo[A] = Hallo())  // ??? 
+2

Không phải là câu trả lời, nhưng ba điều cần lưu ý: bạn có thể muốn đặt tên cho tham số kiểu khác với 'A' để tránh nhầm lẫn với (khác)' A' trong 'scala.collection 'đã tìm thấy. immutable.Set [A] 'message; thực tế quan trọng về cả 'Set' và' Hallo' của bạn là chúng không biến đổi (trái với 'List'); và biên dịch dòng cuối cùng của bạn có thể không làm những gì bạn muốn. –

+1

Trong khi 'lớp Bar [A] (hallo: Hallo [A] = Hallo.apply)' nếu bạn thay đổi nó để sử dụng 'Hallo.apply()' nó hoạt động tốt. Bạn _should_ có thể để lại các parens off, vì vậy nó phải được thực sự bối rối ở đây. Nó cho rằng bạn đang truyền hàm được áp dụng một phần 'Hallo.apply' thay vì gọi' apply' mà không có đối số. (Thông báo lỗi cho biết nó tìm thấy loại '[A]() Hallo [A]'.) – DaoWen

Trả lời

5

Bạn có thể xác định loại trực tiếp vào phương pháp empty thay vì phải thêm các thiết lập thêm dấu ngoặc/niềng răng và loại chú thích:

class Bar[A](set: Set[Foo[A]] = Set.empty[Foo[A]]) 

Đối với lý do tại sao những suy luận kiểu thất bại, thấy những câu hỏi này :

Cập nhật:

Tôi xin lỗi, câu trả lời vội vàng của tôi đã hết. Vấn đề trong bài viết ở trên không thực sự liên quan đến vấn đề này. @TravisBrown thực hiện một điểm rất tốt trong bình luận của mình ở trên. Điều này dường như làm việc lúc đầu:

class Bar[A](set: Set[A] = Set.empty) 

Nhưng nếu bạn thực sự cố gắng để gọi các nhà xây dựng nó không thành công tại sử dụng tại chỗ:

new Bar[Int] 
// <console>:9: error: type mismatch; 
// found : scala.collection.immutable.Set[Nothing] 
// required: Set[Int] 
// Note: Nothing <: Int, but trait Set is invariant in type A. 
// You may wish to investigate a wildcard type such as `_ <: Int`. (SLS 3.2.10) 
// Error occurred in an application involving default arguments. 
//    new Bar[Int] 

Điều này cho thấy trình biên dịch không buộc các tham số mặc định để có giá trị cho tất cả A, chỉ dành cho một số A. Họ có thể chọn như vậy, do đó bạn có thể làm một cái gì đó như thế này:

scala> case class MyClass[T](set: Set[T] = Set(0)) 
defined class MyClass 

scala> MyClass() // defaults to MyClass[Int] 
res0: MyClass[Int] = MyClass(Set(0)) 

scala> MyClass(Set('x)) // but I can still use other types manually 
res1: MyClass[Symbol] = MyClass(Set('x)) 

Tuy nhiên, bất kỳ loại lồng với kiểu tham số không gõ kiểm tra tại địa điểm khai trong các nhà xây dựng:

class Bar[A](set: Set[Option[A]] = Set.empty) 
// <console>:7: error: polymorphic expression cannot be instantiated to expected type; 
// found : [A]scala.collection.immutable.Set[A] 
// required: Set[Option[?]] 
//  class Bar[A](set: Set[Option[A]] = Set.empty) 

Các suy luận không thất bại nếu các tham số kiểu là ở một vị trí hiệp biến:

class Bar[ A ](set: List[Foo[A]] = List.empty) // OK 

class Bar[ A ](set: Map[Int,Foo[A]] = Map.empty) // OK (unless you use it) 

class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD 
// <console>:8: error: polymorphic expression cannot be instantiated to expected type; 
// found : [A, B]scala.collection.immutable.Map[A,B] 
// required: Map[Foo[?],Int] 
//   class Bar[ A ](set: Map[Foo[A],Int] = Map.empty) // BAD 
//              ^

những đang làm việc vì trình biên dịch chọn Nothing như đồng loại biến thể theo mặc định.Điều này làm việc tốt cho List, nhưng ví dụ thứ hai ở trên không hoạt động nếu bạn thực sự cố gắng gọi nó.

Nguyên nhân gây ra sự kỳ quặc này có lẽ là cách mà Scala xử lý các đối số mặc định. Trình biên dịch tự động thêm một phương thức bổ sung cho đối tượng đồng hành, và sau đó bất cứ nơi nào bạn rời khỏi một đối số, trình biên dịch sẽ tự động thêm một lời gọi phương thức vào phương thức mới trong đối tượng đồng hành để tạo đối số còn thiếu thay thế. Dường như trừu tượng đối số mặc định ra thành một phương thức ngắt một số thứ trong suy luận kiểu sẽ làm việc với một phép gán thông thường.

Tôi nghĩ hầu hết những phát hiện này khá khó hiểu. Những gì tôi lấy đi từ điều này là điều quan trọng là phải thực sự kiểm tra các thông số mặc định của bạn để chắc chắn rằng chúng không phá vỡ độ chính xác của loại khi bạn cố gắng sử dụng chúng!

+0

Vâng, tôi biết các tham số kiểu cho 'rỗng'; Tôi chỉ muốn cho thấy rằng việc đúc hoàn toàn giải quyết loại, không giống như loại dự kiến ​​cho đối số mặc định. Điều này không có ý nghĩa với tôi. Ngoài ra tôi không thấy điều này liên quan đến các câu hỏi liên quan đến 'toSet' mà bạn liên kết. –

+0

Bạn nói đúng, sau khi tôi đăng câu trả lời của mình, tôi nhận ra rằng đây không phải là trường hợp tương tự như hai liên kết khác mà tôi đã đăng. Hãy để tôi làm nhiều hơn một chút đào ... Tuy nhiên, vì nó hoạt động nếu bạn sử dụng một 'List' thay vì một' Set' trong ví dụ của bạn, tôi nghĩ rằng nó có liên quan. – DaoWen

+0

@ 0__ - Tôi đã thực hiện một số chỉnh sửa khá đáng kể cho câu trả lời của tôi, vì vậy bạn có thể muốn đọc lại câu trả lời đó. Tôi vẫn không chắc liệu tôi có trả lời câu hỏi ban đầu của bạn hay không - tôi có thể chỉ thêm nhiều câu hỏi hơn. – DaoWen

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