2011-08-23 8 views
17

¿Cómo puedo usar una declaración de "coincidencia" para identificar el valor de una variable de clase? El siguiente es válida, y no puedo encontrar una variante aceptable - que no sea otra cosa si ... si ... si no ...¿Cómo puedo unir clases en una declaración de "coincidencia" de Scala?

val c: Class[_] = classOf[Int] 
val what = c match { case classOf[Int] => "int!"; case classOf[Float] => "float!" } 

El compilador se queja: error: not found: type classOf

Y, por supuesto , no puedo usar Class[Int] debido a que la información se borra tipo: variantes

c match { case Class[Int] => "int!"; case Class[Float] => "float!" } 
error: type Class of type Class does not take type parameters. 

también he intentado como Int.class, todo fue en vano. (Y realmente no quiero convertir cadenas: creo que es importante que el compilador tome clases renombradas/movidas).

¿Estoy siendo denso o me he topado con un punto ciego de Scala?

+1

Bueno, las respuestas a continuación son correctas (y gracias por las respuestas!) pero cada vez parece que este * es * una especie de agujero feo en Scala. Las clases son únicas, por lo que no hay ninguna razón por la que deba asignárselas a las variables para que coincidan de manera eficiente, ni recurrir a una serie de ifs en cascada, escritos como guardias o declaraciones separadas. Pero así es, aparentemente. – Tim

Respuesta

18

Puede coincidir con los valores de la clase si se crea un identificador estable (es decir. Un val) para ellos,

scala> val c: Class[_] = classOf[Int] 
c: Class[_] = int 

scala> val ClassOfInt = classOf[Int] 
ClassOfInt: java.lang.Class[Int] = int 

scala> val ClassOfFloat = classOf[Float] 
ClassOfFloat: java.lang.Class[Float] = float 

scala> val what = c match { 
    |  case ClassOfInt => "int!" 
    |  case ClassOfFloat => "float!" 
    | } 
what: String = int! 

Tenga en cuenta que no puede coincidir con el tipo (es decir. Clase [Int]), porque borrado significa que los diferentes instanciaciones tipo de clase de [T] son ​​indistinguibles en tiempo de ejecución ... por lo tanto la siguiente advertencia

scala> val what = c match { 
    |  case _: Class[Int] => "int!" 
    |  case _: Class[Float] => "float!" 
    | } 
warning: there were 2 unchecked warnings; re-run with -unchecked for details 
what: java.lang.String = int! 
+1

Identificadores estables - sí, tenía miedo de eso. Horrible. "Tenga en cuenta que no puede coincidir en el tipo (es decir, Class [Int])" - sí, se señaló en la pregunta. ¡Gracias de cualquier forma! – Tim

+0

(También debo tener en cuenta que esta respuesta es potencialmente más eficiente que la siguiente, por lo que está más cerca de lo que estoy buscando. ¡Gracias de nuevo!) – Tim

+1

Una nota importante: el nombre del 'val' debe comenzar con una mayúscula. – vpipkt

26

La comparación de casos detallado funciona:

val what = c match { 
    case q if q == classOf[Int] => "int!" 
    case q if q == classOf[Float] => "float!" 
} 

Por supuesto, ser un identificador minúscula, classOf no debería trabajar directamente en un comunicado el caso de todos modos. Sin embargo, tampoco lo hace un trabajo escapado

case `classOf`[Int] 

en este caso, por lo que tendrá que ir con la if cuerpo de guardia.

+0

Sí, el if-guard funciona ... convirtiendo la sentencia 'case' en un conjunto de sentencias' if/else'. Feo, pero bastante correcto. ¡Gracias! – Tim

+0

solución inteligente a esta pregunta – javadba

0

me encontré con el mismo problema y la colocación de la clase en un 'identificador estable' no era tan práctico . Encontré que la siguiente mejor opción era tener ordenadas declaraciones de 'else if'.

uso de este método:

private def is[T <: AnyRef : Manifest](implicit cls: Class[_]) = 
    cls == manifest[T].runtimeClass 

Puedo escribir:

implicit val arg = cls 
    if (is[ClassA]) ... 
    else if (is[ClassB]) ... 
    ... 
    else throw new IllegalArgumentException("Unknown class: " + cls) 
+0

Ja ja. Acabo de encontrar mi propia respuesta nuevamente, pero no puedo votar por ella. –

0

Considerar la herencia:

val what = c match { 
    case q if classOf[Int].isAssignableFrom(q) => "int!" 
    case q if classOf[Float].isAssignableFrom(q) => "float!" 
} 
Cuestiones relacionadas