重复提示直到输入正确

时间:2011-03-17 03:43:27

标签: scala scala-2.8

我最近正在接收Scala。我以前习惯了C和Java。我想知道是否有更优雅的方式反复询问输入,直到给出正确的输入。

val choiceType = {
      var in = ""
      var pass = false
      do {
    in = readLine()
    pass = in match {
        case "1" => println("Not implemented"); true
        case "2" => println("Not implemented"); true
        case "3" => println("Not implemented"); true
        case "4" => println("Not implemented"); true
        case "5" => println("Thanks for using."); true
        case _ => println("Error input. Please enter again. (Possible value: 1 - 5)"); false
    }
      } while (!pass)
      in.toInt
    }
    if (choiceType == 5) System.exit(0)

我想知道在Scala中是否有更好的方法吗?

5 个答案:

答案 0 :(得分:7)

你可以使用Iterate.continually一遍又一遍地做同样的事情,直到你施加一些停止条件(使用dropWhile),或者你可以使用Iterator.iterate给你以前的如果您想在错误消息中使用它,请使用以下行:

val choiceType = Iterator.iterate(readLine())(line => {
  println("Error input: "+line+".  Please enter again (from 1-5).)")
  readLine()
}).collect(line => line match {
  case "1" => println("Not implemented"); line
  case "2" => println("Not implemented"); line
  case "3" => println("Not implemented"); line
  case "4" => println("Not implemented"); line
  case "5" => println("Thanks for using."); line
}).next.toInt

这种方法的工作方式是从readLine开始,然后如果它需要另一行,它会根据前一行宣布一条错误消息(显然是错误的)并读取另一行。然后使用collect块来选择正确的输入;错误的输入只是没有被收集而落空。在这种情况下,因为你想把它变成一个整数,我只是通过这条线。现在,我们只想要一个好的条目,所以我们得到next并将其转换为int。

你也可以使用递归函数来做类似的事情:

def getChoice: String = {
  val line = readLine()
  line match {
    case "1" => println("Not implemented"); line
    case "2" => println("Not implemented"); line
    case "3" => println("Not implemented"); line
    case "4" => println("Not implemented"); line
    case "5" => println("Thanks for using."); line
    case _ => println("Error, blah blah."); getChoice
  }
}
val choiceType = getChoice.toInt

这里的诀窍是,在输入错误的情况下,您只需再次调用该函数。由于这是函数中发生的最后一件事,Scala将避免真正的函数调用并再次跳转到开头(尾递归),因此您不会溢出堆栈。

答案 1 :(得分:2)

递归FTW,恕我直言。无论如何,我会建议对Rex Kerr的递归解决方案进行一些修改。

def getChoice: String = {
  val line = readLine()
  line match {
    case "1" | "2" | "3" | "4" => println("Not implemented"); line
    case "5" => println("Thanks for using."); line
    case _   => println("Error, blah blah."); getChoice
  }
}

答案 2 :(得分:2)

import io.Source.stdin

val choices = stdin.getLines.collect {
  case "1" => println("Not implemented")
  case "2" => println("Not implemented")
  case "3" => println("Not implemented")
  case "4" => println("Not implemented")
  case "5" => println("Thanks for using.")
              System.exit(0)
}

choices.next

答案 3 :(得分:1)

我会使用递归函数。像这样:

def getChoice: Int = readLine match {
  case x if x < "6" && x > "0" && x.length == 1 => x.toInt
  case _ => println("Error, Possible values: (1 - 5)")
            getChoice
}

答案 4 :(得分:1)

Scala允许您将{ case }块视为PartialFunction特征的实例。 PartialFunction为您提供了一种测试函数是否为特定输入定义的方法。所以你可以像这样重写:

val operation: PartialFunction[String, Unit] = {
  case "1" => println("Not implemented")
  case "2" => println("Not implemented")
  case "3" => println("Not implemented")
  case "4" => println("Not implemented")
  case "5" => println("Thanks for using."); System.exit(0)
}

var input: String = ""

do {
  input = readLine()
} while(!operation.isDefinedAt(input))

operation(input)

如果你想避免使用可变input变量,你也可以使用Iterator.continually()(将表达式转换为无限的Iterator,重复计算表达式)。

val operation = ... // as above
val input = Iterator.continually(readLine()).dropWhile(!operation.isDefinedAt(_)).next
operation(input)

您可以避免使用Iterator的operation方法为collect命名。

Iterator.continually(readLine()).collect {
  case "1" => println("one")
}.next