Ответ 1
Метод Option
сопутствующего объекта apply
служит функцией преобразования из нулевых ссылок:
scala> Option(null)
res4: Option[Null] = None
scala> Option(3)
res5: Option[Int] = Some(3)
Предположим, что у меня есть метод session.get(str: String): String
, но вы не знаете, вернет ли он строку или нуль, потому что она исходит из Java.
Есть ли более простой способ обработать это в Scala вместо session.get("foo") == null
? Может быть, какая-то магия применима как ToOption(session.get("foo"))
, а затем я могу ее обработать в Scala, как
ToOption(session.get("foo")) match {
case Some(_) =>;
case None =>;
}
Метод Option
сопутствующего объекта apply
служит функцией преобразования из нулевых ссылок:
scala> Option(null)
res4: Option[Null] = None
scala> Option(3)
res5: Option[Int] = Some(3)
Объект Option
имеет метод apply
, который выполняет именно это:
var myOptionalString = Option(session.get("foo"));
Обратите внимание, что при работе с объектами 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
Это очень старая тема, но хорошая!
Это правда, что преобразование любого неисключительного результата Try to Option приведет к некоторому...
scala> Try(null).toOption
res10: Option[Null] = Some(null)
... потому что Try - это не проверка на обнуляемость, а просто способ функциональной обработки исключений.
Использование Try для перехвата исключения и преобразования его в Option для удобства покажет None в случае возникновения исключения.
scala> Try(1/0).toOption
res11: Option[Int] = None
Вы хотите сохранить значения, полученные в Try. Это может быть нулевым.
Но верно и то, что стандартная библиотека иногда довольно запутанная...
scala> Try(null).toOption
res12: Option[Null] = Some(null)
scala> Option(null)
res13: Option[Null] = None
Это поведение немного противоречиво, но оно отражает намеренное использование как Try, так и Option.
Вы используете try, чтобы получить то, что выходит из выражения, которое может генерировать исключения, и вас не волнует само исключение.
Значение, которое может выйти, вполне может быть нулевым. Если toOption дал None, вы не могли бы различить исключение и ноль, и это нехорошо!
В автономном режиме вы используете Option для инкапсуляции существования или отсутствия чего-либо. Так что в этом случае Some (null) - None, и это имеет смысл, потому что null в этом случае означает отсутствие чего-либо. Здесь нет никакой двусмысленности.
Важно отметить, что в любом случае ссылочная прозрачность не нарушается, поскольку .toOption не является таким же, как Option()
Если вам действительно необходимо обеспечить ОБА безопасность исключений И нулевую безопасность, и ваш код действительно не нуждается в различении между нулем и исключением, вам просто нужно объединить обе парадигмы! Потому что хорошо, это то, что вы хотите, верно?
Вы можете сделать это одним способом...
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)