I would like to continuously prompt the user to enter a date in a given format, until he/she gets it right.
This is what I’ve done:
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
}
where asDate just uses SimpleDateFormat.parse on the entered String.
Now, this seems to work, but I’m pretty sure it’s not the right way.
I don’t really understand how to handle these chained iterators (since both Iterator.continually and takeWhile return an instance of AbstractIterator).
I have basically two questions:
1) Is there a way to “return” startDate from Iterator.continually? I’ve tried and failed map-ping it. I want this in order to get rid of the var date and date = startDate.
2) If I didn’t want anything to happen between the reads, what would I do with the last foreach? I’ve seen that nothing works if I just remove it (I think because of next() not being invoked), but is it OK to leave it there like this:
takeWhile(_ == None).foreach { date => {}} ?
Is there a better way than the “empty” foreach?
Thanks!
You should use
findinstead oftakeWhile–this will keep dropping entries until a good one comes through. Then you have anOption, so you just needif you don’t want to print anything. If you do want to print something, you can put it into the loop.
I’m not sure that this is dramatically clearer, but it’s definitely shorter and does those things you wanted.
I’d probably use a tail-recursive function instead:
The logic seems a bit clearer to me here.