Повторный запрос до правильного ввода - PullRequest
2 голосов
/ 17 марта 2011

Я недавно забираю Скалу. Я привык к 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 ]

7 голосов
/ 17 марта 2011

Вы можете использовать либо 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 избегает истинного вызова функции и просто переходит к началу (хвостовая рекурсия), поэтому вы не переполните стек.

2 голосов
/ 17 марта 2011
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
2 голосов
/ 17 марта 2011

рекурсия 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
  }
}
1 голос
/ 17 марта 2011

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 () (превращает выражение в бесконечный итератор, который повторно вычисляет выражение).

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

И вы можете избежать присвоения имени operation, используя метод итератора collect.

Iterator.continually(readLine()).collect {
  case "1" => println("one")
}.next
1 голос
/ 17 марта 2011

Я бы использовал рекурсивную функцию.Как то так:

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
}
...