6

我有一些需要调用 Java API 的 Scala 代码

Java API 接受可能为空的参数。当然,我的 Scala 使用Option.

例如,假设我有一个 Java 对象构造函数,Foo(Integer)其中. 我想给它一个 Scala 来称呼它。Integernullbar: Option[Int]

我试过这个

import scala.collection.JavaConversions._
import scala.collection.JavaConverters._

val foo = Foo( bar.getOrElse(null) )

但是得到了这个编译错误

Error:(335, 44) type mismatch;
  found   : Any
  required: Integer
  bar.getOrElse(null),

这样做的正确成语是什么?

4

3 回答 3

5

您不需要 Java 方法来重现此问题:

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._

scala> class Foo(a: java.lang.Integer)
defined class Foo

scala> val bar: Option[Int] = Some(5)
bar: Option[Int] = Some(5)

scala> new Foo(bar.getOrElse(null))
<console>:16: error: type mismatch;
 found   : Any
 required: Integer
              new Foo(bar.getOrElse(null))
                                   ^

问题是Int不可能null,所以类型bar.getOrElse(null)Any

scala> bar.getOrElse(null)
res0: Any = 5

scala> bar.orNull
<console>:15: error: Cannot prove that Null <:< Int.
              bar.orNull
                  ^

因此,您必须将Option's 类型参数转换为可以null在以可空方式解包之前的值。

我能立即想到的最快方法:

scala> new Foo(bar.map(x => x: java.lang.Integer).orNull)
res18: Foo = Foo@cdc45e

编辑:在这里,我想到了一种更通用的方法!

implicit class RichOption[A](o: Option[A]) {
    def toRef[B >: Null](implicit f: A => B): B = o.map(f).orNull
}

现在你可以写了new Foo(bar.toRef):)

于 2014-12-22T22:18:29.163 回答
3

更多喋喋不休:

scala> import runtime.BoxesRunTime.boxToInteger
import runtime.BoxesRunTime.boxToInteger

scala> val x = Some(42)
x: Some[Int] = Some(42)

scala> val y: Option[Int] = None
y: Option[Int] = None

scala> x.fold(null: Integer)(boxToInteger)
res0: Integer = 42

scala> y.fold(null: Integer)(boxToInteger)
res1: Integer = null

当然最好是

scala> x.fold(null: Integer)(i => i: Integer)
res2: Integer = 42

甚至更好

scala> x.fold[Integer](null)(identity)
res3: Integer = 42

scala> y.fold[Integer](null)(identity)
res4: Integer = null
于 2014-12-22T23:52:20.320 回答
3

我一发布问题,就在相关列表中找到了答案(对不起)

这是一个解决方案

val foo = Foo(bar.getOrElse(null).asInstanceOf[java.lang.Integer])

有点笨重。有人有更好的吗?

于 2014-12-22T22:23:04.927 回答