Tập hợp loại Set[A]
phải có phương pháp kiểm tra xem một phần tử thuộc loại A
có trong tập hợp không. Phương thức này (apply
) phải có tham số kiểu A
đại diện cho phần tử đó và tham số đó ở vị trí contravariant. Điều này có nghĩa là các tập không thể là biến thể trong tham số kiểu A
của chúng. Vì vậy, nó không phải là mở rộng của giao diện chức năng mà làm cho nó không thể có các tập bất biến biến đổi, đó là sự tồn tại của phương pháp contravariant apply
.
Và vì lý do thuận tiện, bạn có thể mở rộng giao diện Function1
để có thể truyền các bộ xung quanh và coi chúng là các hàm.
Ngược lại, trừu tượng chuỗi không có phương pháp kiểm tra nếu một phần tử nằm trong chuỗi, nó chỉ có phương pháp lập chỉ mục - apply
lấy chỉ số nguyên và trả về phần tử tại chỉ mục đó. Chuỗi cũng được định nghĩa là hàm, nhưng chức năng của loại Int => A
(là biến thể trong A
), không phải là A => Boolean
, làm bộ.
Nếu bạn muốn biết thêm về mức độ an toàn kiểu sẽ bị hỏng nếu tập hợp được định nghĩa là biến thể trong thông số loại A
, hãy xem ví dụ này trong đó triển khai bộ thực hiện một số văn bản cho các thành viên riêng vì lý do đệm bộ nhớ tra cứu (dưới đây @uV
là chú thích mà vô hiệu hóa việc kiểm tra đúng và expensiveLookup
là có nghĩa là để mô phỏng một cuộc gọi đến một tấm séc tính toán tốn kém nếu một yếu tố nằm trong tập):
import annotation.unchecked.{uncheckedVariance => uV}
trait Set[+A] {
def apply(elem: A @uV): Boolean
}
class CachingSet[+A >: Null] extends Set[A] {
private var lastLookup: (A @uV, Boolean) = (null, false)
private def expensiveLookup(elem: A @uV) = (elem, true)
def apply(elem: A @uV): Boolean = {
if (elem != lastLookup._1) lastLookup = expensiveLookup(elem)
lastLookup._2
}
def lastQueriedElement: A = lastLookup._1
}
object Main extends App {
val css = new CachingSet[String]
val csa: CachingSet[AnyRef] = css
csa.apply(new AnyRef)
val s: String = css.lastQueriedElement // you'll get a ClassCastException here
}
Tôi nghĩ [câu trả lời] (http://stackoverflow.com/a/6183115/358642) đối với câu hỏi đầu tiên bạn liên kết nói nhiều hơn các câu hỏi khác. – Philippe
Nhân tiện, tại sao nếu tôi gọi hàm 'foo' trong câu hỏi được liên kết đầu tiên là foo (Set (" asd ")), nó biên dịch? – Rogach
Tôi nghĩ rằng đó là vì phương pháp 'apply' trong [' SetFactory'] (https://github.com/scala/scala/blob/master/src/library/scala/collection/generic/SetFactory.scala) là linh hoạt đủ để tạo ra các tập hợp các loại phần tử khác nhau mà chỉ là các đối số. – Philippe