Ini adalah fakta kehidupan yang menyedihkan di Scala bahwa jika Anda membuat Instansiate Daftar [Int], Anda dapat memverifikasi bahwa instance Anda adalah Daftar, dan Anda dapat memverifikasi bahwa setiap elemen individu itu adalah Int, tetapi bukan bahwa itu adalah Daftar [ Int], karena dapat dengan mudah diverifikasi:
scala> List(1,2,3) match {
| case l : List[String] => println("A list of strings?!")
| case _ => println("Ok")
| }
warning: there were unchecked warnings; re-run with -unchecked for details
A list of strings?!
Opsi -terperiksa menempatkan kesalahan pada penghapusan tipe:
scala> List(1,2,3) match {
| case l : List[String] => println("A list of strings?!")
| case _ => println("Ok")
| }
<console>:6: warning: non variable type-argument String in type pattern is unchecked since it is eliminated by erasure
case l : List[String] => println("A list of strings?!")
^
A list of strings?!
Mengapa begitu, dan bagaimana cara mengatasinya?
scala
type-erasure
Daniel C. Sobral
sumber
sumber
TypeTag
s .scala 2.10.2
, saya melihat peringatan ini:<console>:9: warning: fruitless type test: a value of type List[Int] cannot also be a List[String] (but still might match its erasure) case list: List[String] => println("a list of strings?") ^
Saya menemukan pertanyaan dan jawaban Anda sangat membantu, tetapi saya tidak yakin apakah peringatan yang diperbarui ini bermanfaat bagi pembaca.Jawaban:
Scala didefinisikan dengan Tipe Erasure karena Java Virtual Machine (JVM), tidak seperti Java, tidak mendapatkan obat generik. Ini berarti bahwa, pada saat dijalankan, hanya kelas yang ada, bukan parameter tipenya. Dalam contoh, JVM tahu itu menangani
scala.collection.immutable.List
, tetapi tidak dengan daftar ini parameternyaInt
.Untungnya, ada fitur di Scala yang memungkinkan Anda menyiasatinya. Itu Manifes . Manifest adalah kelas yang instansnya adalah objek yang mewakili tipe. Karena instance ini adalah objek, Anda dapat menyebarkannya, menyimpannya, dan biasanya memanggil metode. Dengan dukungan parameter implisit, itu menjadi alat yang sangat kuat. Ambil contoh berikut, misalnya:
Saat menyimpan elemen, kami menyimpan "Manifes" juga. Manifest adalah kelas yang instansnya mewakili tipe Scala. Objek-objek ini memiliki informasi lebih banyak daripada JVM, yang memungkinkan kita untuk menguji tipe parameterisasi penuh.
Perhatikan, bagaimanapun, bahwa a
Manifest
masih merupakan fitur yang berkembang. Sebagai contoh keterbatasannya, saat ini tidak tahu apa-apa tentang varians, dan menganggap semuanya ko-varian. Saya berharap ini akan menjadi lebih stabil dan kokoh setelah perpustakaan refleksi Scala, saat ini sedang dalam pengembangan, selesai.sumber
get
Metode dapat didefinisikan sebagaifor ((om, v) <- _map get key if om <:< m) yield v.asInstanceOf[T]
.TypeTag
sebenarnya secara otomatis digunakan pada pencocokan pola? Keren kan?Manifest
param itu sendiri, lihat: stackoverflow.com/a/11495793/694469 "instance [manifest / type-tag] [...] sedang dibuat secara implisit oleh kompiler "Anda dapat melakukan ini menggunakan TypeTags (seperti yang sudah Daniel sebutkan, tapi saya hanya akan menjabarkannya secara eksplisit):
Anda juga dapat melakukan ini menggunakan ClassTags (yang menyelamatkan Anda dari ketergantungan pada scala-reflect):
ClassTags dapat digunakan selama Anda tidak mengharapkan parameter tipe
A
menjadi tipe generik.Sayangnya itu sedikit bertele-tele dan Anda membutuhkan penjelasan @eckecked untuk menekan peringatan kompiler. TypeTag dapat dimasukkan ke dalam pencocokan pola secara otomatis oleh kompiler di masa mendatang: https://issues.scala-lang.org/browse/SI-6517
sumber
[List String @unchecked]
karena tidak menambahkan apa pun ke pencocokan pola ini (Hanya menggunakancase strlist if typeOf[A] =:= typeOf[String] =>
akan melakukannya, atau bahkancase _ if typeOf[A] =:= typeOf[String] =>
jika variabel terikat tidak diperlukan di dalam tubuhcase
).=>
dieksekusi. (Dan ketika kode pada rhs dieksekusi, penjaga memberikan jaminan statis pada jenis elemen. Mungkin ada pemain di sana, tapi aman.)Anda bisa menggunakan
Typeable
kelas tipe dari tak berbentuk untuk mendapatkan hasil yang Anda cari,Contoh sesi REPL,
The
cast
operasi akan menjadi seperti tepat wrt penghapusan mungkin mengingat di-lingkupTypeable
kasus yang tersedia.sumber
l1.cast[List[String]]
kira-kirafor (x<-l1) assert(x.isInstanceOf[String]
) Untuk struktur data besar atau jika gips sering terjadi, ini mungkin overhead yang tidak dapat diterima.Saya datang dengan solusi yang relatif sederhana yang akan mencukupi dalam situasi penggunaan terbatas, pada dasarnya membungkus tipe parameter yang akan menderita dari masalah penghapusan tipe dalam kelas wrapper yang dapat digunakan dalam pernyataan pertandingan.
Ini memiliki output yang diharapkan dan membatasi konten kelas kasus kami ke tipe yang diinginkan, Daftar String.
Lebih detail di sini: http://www.scalafied.com/?p=60
sumber
Ada cara untuk mengatasi masalah penghapusan tipe di Scala. Dalam Mengatasi Jenis Penghapusan dalam pencocokan 1 dan Mengatasi Penghapusan Jenis dalam Pencocokan 2 (Varians) adalah beberapa penjelasan tentang cara membuat kode beberapa pembantu untuk membungkus jenis, termasuk Variance, untuk pencocokan.
sumber
Saya menemukan solusi yang sedikit lebih baik untuk pembatasan bahasa yang tidak biasa ini.
Dalam Scala, masalah penghapusan tipe tidak terjadi dengan array. Saya pikir lebih mudah untuk menunjukkan ini dengan sebuah contoh.
Katakanlah kita memiliki daftar
(Int, String)
, lalu yang berikut ini memberikan peringatan penghapusan tipeUntuk mengatasinya, pertama-tama buat kelas kasus:
maka dalam pencocokan pola lakukan sesuatu seperti:
yang tampaknya bekerja dengan sempurna.
Ini akan membutuhkan perubahan kecil dalam kode Anda untuk bekerja dengan array, bukan daftar, tetapi seharusnya tidak menjadi masalah besar.
Perhatikan bahwa menggunakan
case a:Array[(Int, String)]
masih akan memberikan peringatan penghapusan tipe, sehingga perlu menggunakan kelas kontainer baru (dalam contoh ini,IntString
).sumber
Karena Java tidak tahu tipe elemen yang sebenarnya, saya merasa paling bermanfaat untuk digunakan saja
List[_]
. Lalu peringatan hilang dan kode menggambarkan realitas - itu adalah daftar sesuatu yang tidak diketahui.sumber
Saya ingin tahu apakah ini solusi yang cocok:
Itu tidak cocok dengan kasus "daftar kosong", tetapi memberikan kesalahan kompilasi, bukan peringatan!
Ini di sisi lain tampaknya berhasil ....
Bukankah ini agak lebih baik atau apakah saya kehilangan poin di sini?
sumber
Bukan solusi tetapi cara untuk hidup dengan itu tanpa menyapu di bawah karpet sama sekali: Menambahkan
@unchecked
anotasi. Lihat di sini - http://www.scala-lang.org/api/current/index.html#scala.uncheckedsumber
Saya ingin menambahkan jawaban yang membuat masalah: Bagaimana cara mendapatkan representasi String dari tipe daftar saya saat runtime
sumber
Menggunakan penjaga pola pertandingan
sumber
isInstanceOf
melakukan pemeriksaan runtime berdasarkan pada tipe informasi yang tersedia untuk JVM. Dan informasi runtime itu tidak akan berisi argumen type toList
(karena tipe erasure).