Вызов Java API из Scala с нулевым аргументом

У меня есть некоторый код Scala, который должен вызывать API Java

Java API принимает аргументы, которые могут быть нулевыми. Моя Скала, конечно, использует Option,

Например, допустим, у меня есть конструктор объекта Java Foo(Integer) где Integer может быть null, Я хочу назвать это с учетом Scala bar: 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),

Какова правильная идиома для этого?

3 ответа

Решение

Как только я опубликую вопрос, я найду ответ в соответствующем списке (извините)

Вот решение

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

Вид неуклюжий. У кого-нибудь есть что-нибудь лучше?

Вам не нужен метод 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Тип параметра к чему-то, что может быть 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):)

Больше болтовни:

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
Другие вопросы по тегам