Вызов 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