Подтвердить что ты не робот

"Преобразовать" вариант [x] в x в Scala

Я работаю с воспроизведением для scala (2.1), и мне нужно преобразовать значение "Option [Long]" в "Long".

Я знаю, как делать обратное, я имею в виду:

  def toOption[Long](value: Long): Option[Long] = if (value == null) None else Some(value)

Но в моем случае мне нужно передать значение "Option [Long]" как тип в метод, который принимает "Long". Любая помощь пожалуйста.

4b9b3361

Ответ 1

Во-первых, ваша реализация "противоположного" имеет некоторые серьезные проблемы. Поместив параметр типа с именем Long на метод, который вы затеняете тип Long из стандартной библиотеки. Вероятно, вы имеете в виду следующее:

def toOption(value: Long): Option[Long] =
  if (value == null) None else Some(value)

Даже это немного бессмысленно (поскольку scala.Long не является ссылочным типом и никогда не может быть null), если вы не ссылаетесь на java.lang.Long, который является рецептом боли и путаницы. Наконец, даже если вы имеете дело с ссылочным типом (например, String), вам лучше написать следующее, что в точности эквивалентно:

def toOption(value: String): Option[String] = Option(value)

Этот метод вернет None тогда и только тогда, когда value равен null.

Чтобы решить ваш вопрос, предположим, что мы имеем следующий метод:

def foo(x: Long) = x * 2

Вы не должны, как правило, думать о том, чтобы передать Option[Long] в foo, а скорее "поднять" foo в Option через map:

scala> val x: Option[Long] = Some(100L)
x: Option[Long] = Some(100)

scala> x map foo
res14: Option[Long] = Some(200)

Вся точка Option заключается в моделировании (на уровне типа) возможности "нулевого" значения, чтобы избежать целого класса проблем NullPointerException -y. Использование map на Option позволяет выполнять вычисления по значению, которое может находиться в Option, продолжая моделировать возможность его пуста.

В качестве еще одного ответа можно также использовать getOrElse для "освобождения" от Option, но это обычно не является идиоматическим подходом в Scala (за исключением случаев, когда действительно существует разумное значение по умолчанию).

Ответ 2

Если у вас есть x в качестве опции [Long], x.get даст вам Long.

Ответ 3

Этот метод уже определен в опции [A] и называется get:

scala> val x = Some(99L)
x: Some[Long] = Some(99)

scala> x.get
res0: Long = 99

Проблема в том, что вызов get на None будет вызывать исключение NoSucheElement:

scala> None.get
java.util.NoSuchElementException: None.get

таким образом вы не получите каких-либо преимуществ от использования типа Option.

Таким образом, как указано выше, вы можете использовать getOrElse, если вы можете предоставить разумное значение по умолчанию или обработать исключение.

Идиоматический способ scala будет использовать карту или понимание для понимания

x map (_ + 1)
res2: Option[Long] = Some(100)

или

for (i <- x) yield i +1
res3: Option[Long] = Some(100)

Ответ 4

Опция - способ локализовать побочный эффект (ваша функция может вернуть пустое значение). И хороший стиль, чтобы поднять ваши вычисления на Option (опция - Monad с картой и методами FlatMap).

val x = Option[Long](10) 
x.map { a => a + 10 }

И извлеките значение с ручной обработкой побочного эффекта:

val res = x match {
  case Some(a) => s"Value: $a"
  case None    => "no value"
} 

Ответ 5

Вам нужно решить, что произойдет, если опция None. Предоставляете ли вы значение по умолчанию?

def unroll(opt: Option[Long]): Long = opt getOrElse -1L  // -1 if undefined

unroll(None) // -> -1

Вы также можете создать исключение:

def unroll(opt: Option[Long]): Long = opt.getOrElse(throw 
  new IllegalArgumentException("The option is expected to be defined at this point")
)

unroll(None) // -> exception

В случае, воздержитесь от использования null, если у вас нет оснований для его использования (opt.orNull).

Ответ 6

Как уже упоминалось, getOrElse - это то, что вы ищете, отвечая на свой вопрос напрямую.

Обратите внимание, что для преобразования в параметр вы можете просто:

val myOption = Option(1)

myOption теперь будет Some (1)

val myOption = Option(null)

myOption теперь будет None.