在foreach模式匹配然后做最后一步

时间:2012-07-03 00:28:31

标签: scala playframework playframework-2.0

foreach声明中模式匹配后是否可以执行任何操作? 我想做一个匹配后的步骤,例如设置变量。我也想强制单位返回,因为foreach是String =>单位,默认情况下Scala想要返回最后一个语句。

以下是一些代码:

    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) 
    ) 

更新: 新代码和上下文。还添加了新问题:)它们嵌入在评论中。

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 个答案:

答案 0 :(得分:13)

我不知道您的ctm是什么,但您可以随时执行此操作:

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")
}

注意,如果要使用一段代码作为foreach()的参数,则应使用{}而不是()

答案 1 :(得分:3)

我不会回答你的问题,但我应该注意到在Scala中重新分配变量是一种不好的做法。我建议您重写代码以避免var s。

首先,将您的字符串转换为其他字符串:

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/>"
}

接下来,推它

strings map { out.push(_) }

看起来您push的实施会产生副作用。对你不好,因为这样的方法会使你的程序变得不可预测。通过使push返回元组,您可以轻松避免副作用:

def push(s: String) = {
  ...
  (ctm, last)
}

使用它像:

val (ctm, last) = out.push(str)

<强>更新

当然,需要副作用才能使程序变得有用。我只是说依赖于外部变量的方法比pure更不可预测,因此很难对其进行推理。测试方法没有副作用更容易。

是的,你应该更喜欢val s而不是var s,它会使你的程序更“功能”和无状态。无状态算法是线程安全且非常可预测的。

看起来你的程序本质上是有状态的。至少,尽量保持“功能”和无国籍状态:)

我建议的问题解决方案是:

// 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()
  }

如果没有代码的上下文,很难对此进行测试,因此您应该自己满足自己的需求。我希望我已经回答了你的问题。