简体   繁体   中英

Scala Option map to another Option

Is there a way to avoid having to wrap a potentially null result inside another option when mapping from an option.

option.flatMap(arg => Option(arg.somePotentiallyNullValue))

Eg something like

option.optionMap(arg => arg.somePotentiallyNullValue )

I just have a lot of Java code in our codebase that means forever wrapping the results of maps in further Option calls.

What about implicit conversion from nullable type to Option ? Declare this somewhere in scope:

implicit def toOption[T](x: T) : Option[T] = Option(x)

Later the compiler will figure it out:

option.flatMap(_.somePotentiallyNullValue)

Since flatMap expects Option[T] as a result value, compiler uses toOption implicit conversion like this:

option.flatMap(arg => toOption(arg.somePotentiallyNullValue))

The factory method for Option will turn a null into a None :

scala> val os1: Option[String] = Option(null)
os1: Option[String] = None

Addendum

I may have misunderstood your question...

If you restrict its scope judiciously, you can use an implicit conversion:

scala> implicit def nullable2Option[T >: Null](t: T): Option[T] = if (t == null) None else Some(t)
warning: there were 1 feature warnings; re-run with -feature for details
nullable2Option: [T >: Null](t: T)Option[T]

scala> val os2: Option[String] = "foo"
os2: Option[String] = Some(foo)

scala> val nullS: String = null
nullS: String = null

scala> val os3: Option[String] = nullS
os3: Option[String] = None

This will work any time there's available type information for the compiler to use to drive the attempt to bridge a value of a nullable type to an Option . Eg, when calling a method (where the types are always explicit).

In order to make things easier you could introduce a new type:

implicit class CheckedOption[T](val option:Option[T])

object CheckedOption {
  @inline implicit def toOption[T](checkedOption:CheckedOption[T]):Option[T] =
    checkedOption.option.flatMap(Option.apply)
}

Then in your code, where you use the option instance you do something like this:

def use(o:CheckedOption[String]) = {
  o map { value =>
    value + "-Some"
  } getOrElse "None"
}

val option1:Option[String] = Some(null)
val option2:Option[String] = Some("foo")

use(option1) //> res0: String = None
use(option2) //> res1: String = foo-Some

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM