Как вы перестаете строить Option [Collection] после достижения первого None?
При создании коллекции внутриOption
каждая попытка сделать следующий элемент коллекции может потерпеть неудачу, что также приведет к сбою всей коллекции. После первого отказа сделать член, я хотел бы немедленно сдаться и вернутьсяNone
для всей коллекции. Какой идиоматический способ сделать это в Scala?
Вот один из подходов, который я предложил:
def findPartByName(name: String): Option[Part] = . . .
def allParts(names: Seq[String]): Option[Seq[Part]] =
names.foldLeft(Some(Seq.empty): Option[Seq[Part]]) {
(result, name) => result match {
case Some(parts) =>
findPartByName(name) flatMap { part => Some(parts :+ part) }
case None => None
}
}
Другими словами, если любой вызовfindPartByName
возвращаетсяNone
, allParts
возвращаетсяNone
, Иначе,allParts
возвращаетSome
содержащий коллекциюParts
, все из которых гарантированно действительны. Пустая коллекция в порядке.
Вышеуказанное имеет то преимущество, что перестает звонитьfindPartByName
после первой неудачи. НоfoldLeft
по-прежнему повторяется один раз для каждого имени, независимо.
Вот версия, которая выручает, как толькоfindPartByName
возвращаетNone
:
def allParts2(names: Seq[String]): Option[Seq[Part]] = Some(
for (name <- names) yield findPartByName(name) match {
case Some(part) => part
case None => return None
}
)
В настоящее время я нахожу вторую версию более читабельной, но (а) то, что кажется наиболее читабельным, вероятно, изменится, когда я получу больше опыта со Scala, (б) у меня сложилось впечатление, что раноreturn
не одобряется в Scala, и (c) ни один из них, кажется, не делает происходящее особенно очевидным для меня.
Комбинация «все или ничего» и «отказаться от первого отказа» кажется такой базовой концепцией программирования, я полагаю, что для ее выражения должна быть общая Scala или функциональная идиома.