2010-09-08 39 views
11

Trong phương sai Scala có thể được xác định bằng toán tử phương sai như + và - trên đối số kiểu chung. Ví dụ: loại List là biến thể trong thư viện chuẩn.Khi sử dụng ký hiệu hiệp phương sai hoặc giới hạn chung trong Scala

class List[+A] 

Vì vậy, một chức năng với một danh sách hiệp biến thể được định nghĩa như thế này:

def foo[A](list : List[A]) 

Cũng đúng có thể được mô phỏng với giới hạn chung. Vì vậy, chúng tôi cũng có thể viết điều này

def foo[A](list : List[_:< A]) 

tất nhiên điều này không có ý nghĩa, bởi vì list đã là một biến thể. Nhưng cùng một mẹo có thể được thực hiện cho các loại không phải là biến thể. (như Stack). Tất nhiên, cũng có một kiểu mới có thể được tạo ra từ stack (thừa kế của tập hợp) đó là biến đổi.

Vì vậy, câu hỏi của tôi:

  1. Khi nào được sử dụng giới hạn chung cho đúng? Và khi nào chúng ta nên tạo một loại biến đổi mới?
  2. Giới hạn chung chỉ hữu ích cho phương sai hoặc có thể khai báo nhiều hơn (khái niệm ngôn ngữ).
  3. Nếu chúng chỉ hữu ích cho phương sai, các giới hạn sau đó chỉ để tương thích với Java?

thx trước :)

+1

Tôi tăng gấp đôi câu hỏi này - phương sai là phần khó khăn nhất của Scala và tôi thực sự không hiểu nó khá tốt. "Blah-blah covariant blah xuất hiện ở vị trí tương đối blah-blah": p – Jeriho

+2

Tôi hiểu phương sai khi tôi nhìn vào các định nghĩa của một số đặc điểm chức năng (Function1, Function2, vv) Các đặc điểm chức năng là tất cả các biến thể trên kiểu đầu ra và contravariant trên các kiểu đầu vào (tham số). Ví dụ, một hàm của kiểu «Any => Unit' có thể được sử dụng bất cứ nơi nào một hàm kiểu' String => Unit' được mong đợi, bởi vì hàm 'Any => Unit' có thể lấy một chuỗi làm đầu vào của nó (vì nó có thể lấy bất cứ thứ gì làm đầu vào của nó.) Đây là lý do tại sao các kiểu tham số phương thức là một "vị trí contravariant". –

Trả lời

13

Nếu một loại là biến thể tự nhiên hoặc contravariant, bạn nên khai báo nó như vậy. Người dùng của bạn sẽ cảm ơn bạn vì điều đó. Phương sai của trang web sử dụng thực sự chủ yếu là do Java. Chính xác hơn, một loại như Array[T <: Number] được coi là một cách viết tắt cho một kiểu hiện sinh:

ArrayBuffer[T] forSome { type T <: Number } 

loại Hiện sinh có một cú pháp khá cồng kềnh trong Scala. Đó là loại cố ý, bởi vì chúng tôi không khuyên bạn sử dụng chúng nhiều. Khi nào bạn cần một loại tồn tại?

  1. Để viết tương tự của loại Java có ký tự đại diện, chẳng hạn như List<? extends Number>.
  2. Để viết tương tự của loại thô Java, chẳng hạn như List.

Trong Java, loại thô và loại ký tự đại diện không hoàn toàn giống nhau và không giống như kiểu tồn tại (mặc dù chúng tôi biết chúng không có gì, nhưng thật khó để nêu chính xác chúng là gì).Nhưng chúng đủ gần để tồn tại trong thực tế, do đó Scala bị loại bỏ với việc lập bản đồ chúng thành loại kiểu này.

6
  1. Khi tạo một kiểu generic mới, nói Foo [T], bạn nên cố gắng hết sức để xác định xem loại đó là hiệp biến, contravariant hoặc bất biến và tuyên bố nó Foo [ + T], Foo [-T] hoặc Foo [T] tương ứng. Phải thừa nhận rằng điều này có thể là một chút khó khăn. Tuy nhiên, nó giải phóng người dùng của Foo đưa ra quyết định đó mỗi lần cô ấy cần sử dụng một Foo bằng cách sử dụng giới hạn chung. Trong ngắn hạn: thích phương sai khai báo trang web hơn phương sai trang web cuộc gọi khi phương sai là thuộc tính của chính loại đó.

BTW, Lập trình trong sách Scala của Martin Odersky, Lex Spoon và Bill Venners có một số biển tuyệt vời về phương sai. Xem Chương 19 Loại Parametrization.

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