Ini disebut batasan tipe umum . Mereka memungkinkan Anda, dari dalam kelas tipe-parameter atau sifat, untuk lebih jauh membatasi salah satu parameter jenisnya. Ini sebuah contoh:
case class Foo[A](a:A) { // 'A' can be substituted with any type
// getStringLength can only be used if this is a Foo[String]
def getStringLength(implicit evidence: A =:= String) = a.length
}
Argumen implisit evidencedisediakan oleh kompiler, iff Aadalah String. Anda dapat menganggap itu sebagai bukti bahwa Aadalah Stringargumen --the itu sendiri tidak penting, hanya mengetahui bahwa itu ada. [edit: baiklah, secara teknis itu sebenarnya penting karena itu merupakan konversi implisit dari Ake String, yang memungkinkan Anda menelepon a.lengthdan tidak meminta kompiler berteriak kepada Anda]
Sekarang saya bisa menggunakannya seperti ini:
scala> Foo("blah").getStringLength
res6: Int = 4
Tetapi jika saya mencoba menggunakannya dengan Foosesuatu yang mengandung selain String:
scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]
Anda dapat membaca kesalahan itu sebagai "tidak dapat menemukan bukti bahwa Int == String" ... itu sudah seharusnya! getStringLengthmemaksakan pembatasan lebih lanjut pada jenis dari Aapa yang Foosecara umum mengharuskan; yaitu, Anda hanya dapat meminta getStringLengthpada a Foo[String]. Batasan ini diberlakukan pada waktu kompilasi, yang keren!
<:<dan <%<bekerja serupa, tetapi dengan sedikit variasi:
A =:= B berarti A harus persis B
A <:< Bberarti A harus merupakan subtipe B (analog dengan batasan tipe sederhana<: )
A <%< Bberarti A harus dapat dilihat sebagai B, mungkin melalui konversi implisit (analog dengan batasan tipe sederhana <%)
Cuplikan oleh @retronym ini adalah penjelasan yang bagus tentang bagaimana hal seperti ini dapat diselesaikan dan bagaimana batasan tipe umum membuatnya lebih mudah sekarang.
TAMBAHAN
Untuk menjawab pertanyaan tindak lanjut Anda, diakui contoh yang saya berikan cukup dibuat-buat dan tidak jelas berguna. Tapi bayangkan menggunakannya untuk mendefinisikan sesuatu seperti List.sumIntsmetode, yang menambahkan daftar bilangan bulat. Anda tidak ingin mengizinkan metode ini dipanggil pada yang lama List, hanya a List[Int]. Namun Listkonstruktor tipe tidak dapat dibatasi; Anda masih ingin dapat memiliki daftar string, foo, bar, dan apa pun. Jadi dengan menempatkan batasan tipe umum sumInts, Anda dapat memastikan bahwa hanya metode yang memiliki kendala tambahan yang hanya dapat digunakan pada a List[Int]. Pada dasarnya Anda sedang menulis kode kasus khusus untuk beberapa jenis daftar.