2

我想不断提示用户以给定格式输入日期,直到他/她正确为止。

这就是我所做的:

def readDate(prompt: String): Date = {
    var date: Option[Date] = None
    Iterator.continually {
      val startDateString = readLine(prompt)
      val startDate = catching(classOf[ParseException]).opt(asDate(startDateString))
      date = startDate
      startDate
    }.takeWhile(_ == None).foreach {
      date =>
        println("Incorrect format. Try again.")
    }
    date.get
  }

asDateSimpleDateFormat.parse在输入的字符串上使用。

现在,这似乎可行,但我很确定这不是正确的方法。

我真的不明白如何处理这些链式迭代器(因为 Iterator.continually 和 takeWhile 都返回 AbstractIterator 的实例)。

我基本上有两个问题:

1)有没有办法从“返回startDateIterator.continually?我已经尝试过并且失败了 - mapping 它。我想要这个以摆脱var dateand date = startDate

2)如果我不想在读取之间发生任何事情,我会如何处理最后一个 foreach?我已经看到,如果我只是将其删除(我认为是因为 next() 没有被调用),则没有任何效果,但是可以像这样将它留在那里:

takeWhile(_ == None).foreach { date => {}}?

有没有比“空”foreach 更好的方法?

谢谢!

4

2 回答 2

3

您应该使用find而不是takeWhile--this 将继续删除条目,直到一个好的条目出现。然后你有一个Option,所以你只需要

def readDate(prompt: String): Date = {
  Iterator.continually {
    catching(classOf[ParseException]).opt(asDate( readLine(prompt) ))
  }.find(_.isDefined).get
}

如果你不想打印任何东西。如果您确实想打印某些内容,可以将其放入循环中。

def readDate(prompt: String): Date = {
  Iterator.continually {
    catching(classOf[ParseException]).opt(asDate( readLine(prompt) )) match {
      case None =>
        println("Incorrect format.  Try again.")
        None
      case x => x
    }
  }.find(_.isDefined).get
}

我不确定这是否更清晰,但它肯定更短并且可以完成您想要的那些事情。

我可能会改用尾递归函数:

import annotation.tailrec
@tailrec def readDate(prompt: String, again: Boolean = false): Date = {
  if (again) println("Incorrect format.  Try again.")
  catching(classOf[ParseException]).opt(asDate( readLine(prompt) )) match {
    case Some(date) => date
    case None => readDate(prompt, true)
  }
}

这里的逻辑对我来说似乎更清楚一些。

于 2013-01-15T23:53:48.843 回答
2

我会把它写成

def readDate(prompt: String): Date = 
  try asDate(readLine(prompt))
  catch { case e: ParseException => 
    println("Incorrect format. Try again.")
    readDate(prompt)
  }
于 2013-01-16T11:10:01.403 回答