scala fungsi generik untuk mengonversi tipe apa pun menjadi argumen tipe generik tertentu

Apakah mungkin untuk menulis fungsi generik yang menerima nilai bertipe "Any" dan argumen tipe generik mengatakan "T" dan mengembalikan Option[T] dengan memeriksa tipe runtime dari nilai yang diteruskan?

Saya mencoba di repl (Scala versi 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66))

def cast[T](x: Any): Option[T] = x match {
case v: T => Some(v)
case _ =>  Option.empty[T]
}

Saya mendapat peringatan:

 warning: abstract type pattern T is unchecked since it is eliminated by erasure
           case v: T => Some(v)

Bagaimana cara saya meneruskan tipe kelas dan melakukan pemeriksaan tipe eksplisit alih-alih generik?

P.S. jelas karena penghapusan tipe, kode di atas meledak. Contoh interaksi balasan :

scala> val x :Any = 123                                                                                    
x: Any = 123                                                                                               

scala> cast[Int](x)                                                                                        
res0: Option[Int] = Some(123)                                                                              

scala> cast[String](x)                                                                                     
res1: Option[String] = Some(123)                                                                           

scala> val x :Any = "dfg"                                                                                  
x: Any = dfg                                                                                               

scala> cast[Int](x)                                                                                        
res2: Option[Int] = Some(dfg)                                                                              

scala> cast[Int](x).get                                                                                    
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer                         
  at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)                                          
  ... 33 elided   

person sas1138    schedule 14.01.2017    source sumber


Jawaban (1)


Anda memerlukan ClassTag untuk jenis runtime:

def cast[T: ClassTag](x: Any): Option[T] = x match {
  case v: T => Some(v)
  case _ =>  Option.empty[T]
}

println(cast[Int](1))
println(cast[Int]("hello"))

Hasil:

Some(1)
None
person Yuval Itzchakov    schedule 14.01.2017
comment
terima kasih atas balasan cepatnya. bacaan lebih lanjut : docs.scala-lang.org/overviews/reflection/ - person sas1138; 14.01.2017
comment
Perhatikan bahwa ini memiliki batasan: val list = List("a", "b") ; cast[List[Int]](list) - person Michael Zajac; 14.01.2017
comment
@MichaelZajac Memang. Saya akan segera memperluas jawabannya menjadi lebih umum. - person Yuval Itzchakov; 14.01.2017
comment
@MichaelZajac jika pemahaman saya benar, masalahnya adalah karena tipe level kedua bersarang, dibungkus dalam Daftar (atau konstruktor tipe data apa pun yang dibungkus). - person sas1138; 16.01.2017