6

foreach在语句中的模式匹配之后可以做任何事情吗?
我想做一个匹配后的步骤,例如设置一个变量。我还想强制返回 Unit,因为我foreach的 is String => Unit,默认情况下 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)
}
4

2 回答 2

18

我不知道你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() 的参数时,您应该使用{}而不是。()

于 2012-07-03T01:30:48.983 回答
3

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

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

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)

更新:

当然,要使程序有用,需要副作用。我只是说依赖于外部变量的方法比纯粹的方法更难预测,很难推理。没有副作用的测试方法更容易。

是的,你应该更喜欢vals 而不是vars,它使你的程序更“实用”和无状态。无状态算法是线程安全的并且非常可预测。

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

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

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

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

于 2012-07-03T02:00:32.867 回答