Обгортання нульового методу повернення на Java з опцією в Scala?


107

Припустимо, у мене є метод, session.get(str: String): Stringале ви не знаєте, поверне він вам рядок або нуль, оскільки він походить від Java.

Чи є простіший спосіб лікування цього в Scala замість session.get("foo") == null? Можливо, якась магія застосовується на кшталт, ToOption(session.get("foo"))і тоді я можу ставитися до неї так, як Скала

ToOption(session.get("foo")) match {
    case Some(_) =>;
    case None =>;
}

4
Докладніше про варіанти хитрощів див. Blog.tmorris.net/scalaoption-cheat-sheet
Landei

4
Посилання вище повинно бути blog.tmorris.net/posts/scalaoption-cheat-sheet .
Яцек Ласковський

Відповіді:


182

Метод Optionоб'єкта-супутника applyвиконує функцію перетворення з нульових посилань:

scala> Option(null)
res4: Option[Null] = None

scala> Option(3)   
res5: Option[Int] = Some(3)

19

OptionОб'єкт має applyметод , який робить саме те, що:

var myOptionalString = Option(session.get("foo"));

5

Зауважте, що при роботі з об’єктами Java він не працюватиме так, як очікувалося:

val nullValueInteger : java.lang.Integer = null
val option: Option[Int] = Option(nullValueInteger)
println(option)  // Doesn't work - zero value on conversion

val nullStringValue : String = null
val optionString: Option[String] = Option(nullStringValue)
println(optionString) // Works - None value

1
Я бігав зі скалою 2.11.8. Другий рядок кинув NullPointerException. Шостий рядок отримав Some (null), а не None, як ви очікували.
Джон Лін

1. Використовується Деякі замість Option у optionString - Змінено оригінальну відповідь. 2. Перевірено лише в Scala 2.12.5
DekelM

-3

Це дуже стара тема, але приємна!

Це правда, що перетворення будь-якого не виключення результату "Спроба до варіанту" призведе до деякого ...

scala> Try(null).toOption
res10: Option[Null] = Some(null)

... тому що спробуйте не про перевірку зведеності нанівець, а просто спосіб функціонального поводження з винятками.

Використання Спробуйте знайти виняток і перетворити його на Варіант для зручності не відображатиметься лише у випадку, якщо виняток трапиться.

scala> Try(1/0).toOption
res11: Option[Int] = None

Ви хочете зберегти цінності, що виходять із спробувати. Це може бути недійсним.

Але також правда, що стандартна ліб часом досить заплутана ...

scala> Try(null).toOption
res12: Option[Null] = Some(null)

scala> Option(null)
res13: Option[Null] = None

Така поведінка трохи непослідовна, проте вона відображає навмисне використання як Спробуйте, так і Варіант.

Ви використовуєте спробуйте отримати все, що виходить із виразу, який може кинути винятки, і вас не хвилює саме виняток.

Значення, яке може вийти, може бути нульовим. Якщо toOption дав None, ви не могли розмежувати виняток і null , і це не дуже!

Автономно, ви використовуєте Option, щоб інкапсулювати існування чи ні чогось. Так що в такому випадку Some (null) є None, і це має сенс, тому що null в цьому випадку являє собою відсутність чогось. Тут немає двозначності.

Важливо зауважити, що в будь-якому випадку прозорість референціалів не порушена, оскільки .toOption не збігається з Option ()

Якщо вам дійсно потрібно забезпечити БОЛЬНУ безпеку винятків І нульову безпеку, і ваш код дійсно не потребує розмежування між null та винятком , вам просто потрібно поєднувати обидві парадигми! Бо добре, це те, що ти хочеш, правда?

Ви можете це зробити одним способом ...

scala> Try(Option(null)).getOrElse(None)
res23: Option[Null] = None

scala> Try(Option(3/0)).getOrElse(None)
res24: Option[Int] = None

scala> Try(Option(3)).getOrElse(None)
res25: Option[Int] = Some(3)

... чи інший ...

scala> Try(Option(null)).toOption.flatten
res26: Option[Null] = None

scala> Try(Option(3/0)).toOption.flatten
res27: Option[Int] = None

scala> Try(Option(3)).toOption.flatten
res28: Option[Int] = Some(3)

... або сміхотворніші з них чужі ...

scala> Option(Try(null).getOrElse(null))
res29: Option[Null] = None

scala> Option(Try(3/0).getOrElse(null))
res30: Option[Any] = None

scala> Option(Try(3).getOrElse(null))
res31: Option[Any] = Some(3)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.