Coincidencia de patrón en foreach y luego hacer un paso final
Frecuentes
Visto 13,621 equipos
6
¿Es posible hacer algo después de una coincidencia de patrón en un foreach
¿declaración?
Quiero hacer un paso posterior a la coincidencia, por ejemplo, para establecer una variable. También quiero forzar la devolución de una Unidad ya que mi foreach
es String => Unit, y por defecto Scala quiere devolver la última declaración.
Aquí hay un código:
Iteratee.foreach[String](_ match {
case "date" => out.push("Current date: " + new Date().toString + "<br/>")
case "since" => out.push("Last command executed: " + (ctm - last) + "ms before now<br/>")
case unknow => out.push("Command: " + unknown + " not recognized <br/>")
} // here I would like to set "last = ctm" (will be a Long)
)
ACTUALIZADO: Nuevo código y contexto. También se agregaron nuevas preguntas :) Están incrustadas en los comentarios.
def socket = WebSocket.using[String] { request =>
// Comment from an answer bellow but what are the side effects?
// By convention, methods with side effects takes an empty argument list
def ctm(): Long = System.currentTimeMillis
var last: Long = ctm
// Command handlers
// Comment from an answer bellow but what are the side effects?
// By convention, methods with side effects takes an empty argument list
def date() = "Current date: " + new Date().toString + "<br/>"
def since(last: Long) = "Last command executed: " + (ctm - last) + "ms before now<br/>"
def unknown(cmd: String) = "Command: " + cmd + " not recognized <br/>"
val out = Enumerator.imperative[String] {}
// How to transform into the mapping strategy given in lpaul7's nice answer.
lazy val in = Iteratee.foreach[String](_ match {
case "date" => out.push(date)
case "since" => out.push(since(last))
case unknown => out.push(unknown)
} // Here I want to update the variable last to "last = ctm"
).mapDone { _ =>
println("Disconnected")
}
(in, out)
}
2 Respuestas
18
No se cual es tu ctm
es, pero siempre puedes hacer esto:
val xs = List("date", "since", "other1", "other2")
xs.foreach { str =>
str match {
case "date" => println("Match Date")
case "since" => println("Match Since")
case unknow => println("Others")
}
println("Put your post step here")
}
Tenga en cuenta que debe usar {}
en lugar de ()
cuando quieras usar un bloque de código como argumento de foreach().
Respondido 03 Jul 12, 02:07
3
No responderé a su pregunta, pero debo señalar que reasignar variables en Scala es una mala práctica. Le sugiero que reescriba su código para evitar var
s.
Primero, transforma tus cadenas en otra cosa:
val strings = it map {
case "date" => "Current date: " + new Date().toString + "<br/>"
case "since" => "Last command executed: " + (ctm - last) + "ms before now<br/>"
case unknow => "Command: " + unknown + " not recognized <br/>"
}
Luego, empújalo
strings map { out.push(_) }
Parece que su implementación de push
tiene efectos secundarios. Malo para ti, porque tales métodos hacen que tu programa sea impredecible. Puede evitar fácilmente los efectos secundarios haciendo push
devolver una tupla:
def push(s: String) = {
...
(ctm, last)
}
Y usándolo como:
val (ctm, last) = out.push(str)
Actualizar:
Por supuesto, se necesitan efectos secundarios para que los programas sean útiles. Solo quise decir que los métodos que dependen de variables externas son menos predecibles que puro uno, es difícil razonar al respecto. Es más fácil probar métodos sin efectos secundarios.
Sí, deberías preferir val
se acabó var
s, hace que su programa sea más "funcional" y sin estado. Los algoritmos sin estado son seguros para subprocesos y muy predecibles.
Parece que su programa tiene estado por naturaleza. Al menos, trate de mantenerse lo más "funcional" y sin estado que pueda :)
Mi solución sugerida de su problema es:
// By convention, methods with side effects takes an empty argument list
def ctm(): Long = // Get current time
// Command handlers
def date() = "Current date: " + new Date().toString + "<br/>"
def since(last: Long) = "Last command executed: " + (ctm() - last) + "ms before now<br/>"
def unknown(cmd: String) = "Command: " + unknown + " not recognized <br/>"
// In your cmd processing loop
// First, map inputs to responses
val cmds = inps map {
case "date" => date()
case "since" => since(last)
case unk => unknown(unk)
}
// Then push responses and update state
cmds map { response =>
out.push(response)
// It is a good place to update your state
last = ctm()
}
Es difícil probar esto sin el contexto de su código, por lo que debe adaptarlo a sus necesidades. Espero haber respondido a tu pregunta.
Respondido 03 Jul 12, 09:07
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas scala playframework playframework-2.0 or haz tu propia pregunta.
Gracias por tu respuesta. Sin embargo, tengo algunas preguntas/observaciones. ¿De qué manera quieres decir que tener efectos secundarios es malo? El único propósito de out.push es tener un efecto secundario de escritura más específico en el websocket. empuje devuelva una Unidad, ya que solo empuja a String a través de un zócalo, por lo que no puedo asignar la tupla allí. La recomendación de val en lugar de var es interesante. Mis habilidades funcionales pueden faltar y agradecería mucho su respuesta actualizada en este contexto. last es una variable de instancia que debe contener currentTimeInMillies del último comando recibido a través del websocket. cdm es una definición - granjero
Sí, gracias, entiendo que el contexto es vago, actualicé mi respuesta para dar un contexto más amplio. Tu respuesta es genial. Todavía no entiendo su significado de los efectos secundarios, por ejemplo, ¿qué efecto secundario está causando la fecha ()? ¿También mi Iteratee no es compatible con el mapa? - granjero
¿De dónde vienen tus Iteratee? ¿Probaste Iteratee.map? ¿Compiló o te dio un error? - lambda