Опция обработки Scala [T] - PullRequest
       65

Опция обработки Scala [T]

0 голосов
/ 16 декабря 2011

У меня есть Scala Option[T]. Если значение Some(x), я хочу обработать его процессом, который не возвращает значение (Unit), но если это None, я хочу напечатать ошибку.

Я могу использовать следующий код для этого, но я понимаю, что более идиоматическим способом является обработка Option[T] как последовательности и использование map, foreach и т. Д. Как это сделать?

opt match {
  case Some(x) => // process x with no return value, e.g. write x to a file
  case None => // print error message
}

Ответы [ 5 ]

6 голосов
/ 16 декабря 2011

Я думаю, что явное сопоставление с образцом лучше всего подходит для вашего случая использования.

3 голосов
/ 16 декабря 2011

В Scala Option, к сожалению, отсутствует способ сделать именно это.Я добавляю один:

class OptionWrapper[A](o: Option[A]) {
  def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)

, который имеет немного более приятное (на мой взгляд) использование

op.fold{ println("Empty!") }{ x => doStuffWith(x) }

Вы можете видеть из того, как определено, что map / getOrElse может бытьиспользуется вместо сопоставления с образцом.

В качестве альтернативы, Either уже имеет метод fold.Таким образом, вы можете

op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }

, но это немного неуклюже, учитывая, что вы должны предоставить левое значение (здесь (), то есть Unit) и затем определить функцию для этого, а не просто указать, что выхочу, чтобы это произошло на None.

Сравнение с образцом также неплохо, особенно для более длинных блоков кода.Для коротких накладные расходы в матче начинают мешать очкам.Например:

op.fold{ printError }{ saveUserInput }

имеет намного меньше синтаксических издержек, чем

op match {
  case Some(x) => saveUserInput(x)
  case None => printError
}

, и поэтому, как только вы ожидаете, это намного легче понять.

3 голосов
/ 16 декабря 2011

Я бы рекомендовал просто и безопасно использовать opt.get, что само по себе выдает исключение NoSuchElementException, если opt равно None.Или, если вы хотите создать собственное исключение, вы можете сделать это:

val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T
2 голосов
/ 16 декабря 2011

Как говорит @missingfaktor, вы находитесь в точном сценарии, где сопоставление с образцом дает наиболее читаемые результаты.Если в Option есть значение, вы хотите что-то сделать, если не хотите делать что-то еще.

Хотя существуют различные способы использования карты и других функциональных конструкций в типах Option, они обычно полезны, когда:

вы хотите использовать регистр Some и игнорировать регистр None, например, в вашем случае

opt.map(writeToFile(_)) //(...if None just do nothing)

или вы хотите объединить операции для нескольких вариантов и дать результат только тогда, когда все онинекоторые.Например, один из способов сделать это:

val concatThreeOptions = 
for {
  n1 <- opt1
  n2 <- opt2
  n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
                     // we will either write them all to a file or none of them

, но ни один из них, похоже, не ваш случай

2 голосов
/ 16 декабря 2011

Сопоставление с образцом - лучший выбор здесь.

Однако, если вы хотите обрабатывать Option как последовательность и отображать ее, вы можете сделать это, потому что Unit - это значение:

opt map { v =>
  println(v) // process v (result type is Unit)
} getOrElse {
  println("error")
}

Кстати, печать ошибки - это своего рода «анти-шаблон», поэтому лучше все равно выдать исключение:

opt.getOrElse(throw new SomeException)
...