2011-05-29 11 views
9

Necesito analizar algunos mensajes. Los primeros 4 bytes de un mensaje identifican el tipo de mensaje, por lo que, al usarlo, puedo instanciar un objeto del tipo adecuado. Para hacer de esto una operación eficiente, pensé que crearía un mapa hash donde la clave son los primeros 4 bytes, y el valor es el constructor del objeto. Puedo buscar el constructor e invocarlo.Tratando un constructor como una función en Scala: ¿cómo poner constructores en un mapa?

Después de todo, los constructores son solo funciones, y no debería haber ningún problema para poner funciones en un mapa. Resulta que estoy teniendo algunas dificultades con esto porque no sé cómo expresar la referencia al constructor correctamente.

Para concretar con un ejemplo simplificado, supongamos que tenemos una clase de base de mensajes, MsgBase, y un par de subclases, MsgA y . Si creo un objeto complementario para cada uno de los mensajes y le agrego una función de fábrica, puedo hacer la matriz sin ningún problema al usar esas funciones.

Aquí hay una muestra simplificada que toma el mensaje como una cadena.

class MsgBase(message: String) { } 

class MsgA(message: String) extends MsgBase(message) { } 

object MsgA { def makeIt(message: String): MsgA = new MsgA(message) } 

y donde MsgB es similar. Entonces puedo hacer el mapa:

val cm = Map[String, (String) => MsgBase]("a" -> MsgA.makeIt, "b" -> MsgB.makeIt) 

val myMsg = cm("a")("a.This is the message") 

Parece como si tuviera que ser capaz de hacer referencia al constructor mensaje de objeto directamente en la expresión construir el mapa, en lugar de utilizar la función trivial en el objeto acompañante, pero no he No encontré ninguna forma de expresar eso. ¿Hay alguna manera?

+0

'después de todo, los constructores son solo funciones' ¿Lo son? ¿Quién dice eso? Mi impresión es diferente Normalmente, puedo invocar una función varias veces en un objeto y no tengo que llamar 'nuevo', solo para nombrar las dos primeras diferencias, que me vienen a la mente. –

+0

@ user-unknown sí, los constructores en realidad son funciones (estáticas): (i) el uso de 'nuevo' es sintaxis adicional solo para recordarle que este es un tipo particular de función (muchos idiomas omiten la palabra clave, incluido el caso de Scala) constructores de clase). (ii) Es un método estático en esencia; no llama al constructor sobre un objeto existente (no es un método). –

Respuesta

12

Trate

"a" -> (new MsgA(_)) 

(se necesitan todos los paréntesis).

Incluso si esto no funciona, usted podría, por supuesto, siempre definir la función de forma explícita:

"a" -> ((s: String) => new MsgA(s)) 
+0

¿quisiste decir '" a "-> (new MsgA (_))'? –

+0

Muchas gracias. Justo lo que estaba buscando: literal de función de forma corta con marcador de posición (página 191 en Programación en Scala, 2da ed., en caso de que alguien quiera leer más) – Willard

+0

@Kim - Supongo que era una cadena, no una var, tan seguro, '" a "'. –

2
val cm = Map[String, (String) => MsgBase]("a" -> (new MsgA(_)), "b" -> (new MsgB(_))) 
3

Para este caso, sería mejor utilizar clases de casos, lo que le proporciona automáticamente las funciones de creando nuevos objetos.

scala> case class MsgA(message: String) extends MsgBase(message) 
scala> case class MsgB(message: String) extends MsgBase(message) 

para que pueda referirse ellas sólo por su nombre, sin ningún tipo de gastos sintáctica

scala> val m = Map("a"->MsgA, "b"->MsgB) 
m: scala.collection.immutable.Map[java.lang.String,scala.runtime.AbstractFunction1[java.lang.String,Product with MsgBase]] = Map((a,<function1>), (b,<function1>)) 

scala> m("a")("qqq")        
res1: Product with MsgBase = MsgA(qqq) 

Como un enfoque alternativo puede crear objeto acompañante con overrided aplicar el método a mano. Para más detalles, vea Programming scala, chapter 6

Cuestiones relacionadas