2015-07-17 22 views
5

Nel Scala 2.10, il compilatore avverte il codice data:Scala cancellazione del tipo in pattern matching mappa [String, Int]

private def getStrFromOpt[T](opt: Option[T]): String = opt match { 
    case Some(s: String) => s 
    case Some(i: Int) => i.toString() 
    case Some(l: Long) => l.toString() 
    case Some(m: Map[String, Int]) => m map ({ case (k, v) => 
     "(" + k + ", " + v + ")" }) mkString ("(", ", ", ")") 
    case _ => "" 
    } 

con il messaggio non-variable type argument String in type pattern Map[String,Int] is unchecked since it is eliminated by erasure: case Some(m: Map[String, Int]) ....

Come posso eliminare questo avviso? Cosa succede se avrò un Map[String, MyObj] che voglio includere come caso in questo abbinamento? Come posso distinguere i due casi con Mappe parametrizzate?

+0

possibile duplicato di [Come faccio a evitare la cancellazione del tipo su Scala? Oppure, perché non posso ottenere il parametro tipo delle mie raccolte?] (Http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why -cant-i-get-the-tipo-paramete) – Chirlo

risposta

4

puoi usare l'annotazione Scala @unchecked per sopprimere l'avviso, per la tua seconda domanda, ti suggerisco di usare Scala reflection - TypeTag. Sto usando Scala 2.11.4, ecco il codice di esempio, FYI.

import scala.reflect.runtime.{ universe => ru } 
import scala.reflect.runtime.universe.{ typeTag, TypeTag } 

object MapType extends App { 
    def getTypeTag[T: TypeTag](t: T) = typeTag[T].tpe 
    def getTypeTag[T: TypeTag] = ru.typeOf[T] 

    // context bound T: ru.TypeTag cause typeOf 
    // requires implicit parameter 
    def getStrFromOpt[T: TypeTag](opt: Option[T]): String = { 
    opt match { 
     case Some(s: String) => s 
     case Some(i: Int) => i.toString() 
     case Some(l: Long) => l.toString() 
     case Some(m: Map[String, Int] @ unchecked) 
     if getTypeTag[T] =:= getTypeTag[Map[String, Int]] => "Int Map" 
     case Some(m: Map[String, String] @ unchecked) 
     if getTypeTag[T] =:= getTypeTag[Map[String, String]] => "String Map" 
     case _ => "" 
    } 
    } 

    // "Int Map" 
    println(getStrFromOpt(Some(Map("a" -> 2, "b" -> 3)))) 
    // "String Map" 
    println(getStrFromOpt(Some(Map("a" -> "2", "b" -> "3")))) 
} 

In realtà Scala utilizza il modello di cancellazione dei generici proprio come fa Java. Quindi nessuna informazione sugli argomenti di tipo viene mantenuta in fase di esecuzione.

def isIntMap(x: Any) = x match { 
    case m: Map[Int, Int] => true 
    case _ => false 
} 

Per il codice di cui sopra, Scala compilatore non può decidere se m è Map [Int, Int] o meno. Pertanto, isIntMap(Map("a"-> "b")) restituisce true, che sembra non intuitivo. Per avvisare il comportamento di runtime, il compilatore Scala ha emesso quel messaggio non controllato.

Tuttavia, Array è un'eccezione, il suo tipo di elemento viene memorizzato con il valore dell'elemento.

def isIntArray(x: Any) = x match { 
    case a: Array[String] => "yes" 
    case _ => "no" 
} 

scala> isIntArray(Array(3)) 
res1: String = no 

scala> isIntArray(Array("1")) 
res2: String = yes