Как мне переписать эту java функцию в scala, сохраняя тот же необязательный входной параметр? - PullRequest
0 голосов
/ 07 января 2020

У меня есть следующий метод в java

protected <T> T getObjectFromNullableOptional(final Optional<T> opt) {
    return Optional.ofNullable(opt).flatMap(innerOptional -> innerOptional).orElse(null);
}

Требуется java Optional, который может сам по себе быть null (я знаю, это действительно плохо, и мы собираемся чтобы исправить это в конце концов). И он оборачивает его другим Optional, поэтому он становится либо Some(Optional<T>), либо None. Тогда это flatMapped, поэтому мы возвращаемся Optional<T> или None и, наконец, применяем orElse(), чтобы получить T или null.

Как мне написать тот же метод с тем же java .util. Опционально в scala?

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
    ???

Я пытался

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
  Optional.ofNullable(opt).flatMap(o  => o).orElse(null)

Но это дает мне Type mismatch ошибку

Обязательно: Функция [_>: Необязательно [T], Необязательно [NotInferedU]]

Найдено: Ничего => Ничего

Я пытался

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
  Option(opt).flatMap(o => o).getOrElse(null)

Но это дает мне

Не удается разрешить перегруженный метод 'flatMap'

Редактировать Я не упомянул, что использую scala 2.11. Я считаю, что решение @ tefanobaghino предназначено для scala 2.13, но оно привело меня к правильному пути. Я поставил свое окончательное решение в комментариях под этим решением

1 Ответ

1 голос
/ 07 января 2020

Последняя ошибка вызывает несколько подозрений: похоже, вы заключаете Java Optional в Scala Option. Вместо этого я бы ожидал, что это не удастся, потому что вы пытаетесь flatMap другого типа, что-то вроде

error: type mismatch;
 found   : java.util.Optional[T] => java.util.Optional[T]
 required: java.util.Optional[T] => Option[?]

Это, кажется, соответствует вашему требованию:

import java.util.Optional

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).orElse(Optional.empty).orElse(null.asInstanceOf[T])

assert(getObjectFromNullableOptional(null) == null)
assert(getObjectFromNullableOptional(Optional.empty) == null)
assert(getObjectFromNullableOptional(Optional.of(1)) == 1)

Вы можете поиграть с этим здесь, в Scast ie.

Обратите внимание, что asInstanceOf скомпилирован с приведением, а не с фактическим вызовом метода, поэтому этот код не будет выбрасывать a NullPointerException.

Вы также можете go сделать что-то более близкое к вашему исходному решению, немного помогая выводу типа Scala:

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).flatMap((o: Optional[T]) => o).orElse(null.asInstanceOf[T])

Или альтернативно используя Scala s identity:

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).flatMap(identity[Optional[T]]).orElse(null.asInstanceOf[T])

Для решения, использующего Scala 'Option, вы можете сделать что-то очень близкое:

def getObjectFromNullableOption[T](opt: Option[T]): T =
  Option(opt).getOrElse(None).getOrElse(null.asInstanceOf[T])

Обратите внимание, что вы идете к * Решение 1029 * с Scala Option позволяет избежать явного указания типа функции:

def getObjectFromNullableOption[T](opt: Option[T]): T =
  Option(opt).flatMap(identity).getOrElse(null.asInstanceOf[T])

Я не совсем уверен в деталях, но я считаю, что проблема заключается в что при использовании java.util.Optional вы передаете Scala Function в Optional.flatMap, что занимает Java Function. Компилятор Scala может преобразовать это автоматически для вас, но, очевидно, вы должны указать c и указать тип, чтобы это работало, по крайней мере, в этом случае.

Примечание относительно вашего исходного кода: вы требуется T, чтобы быть супертипом Null, но это не обязательно.

У вас есть лучший контекст относительно того, что вы делаете, но в качестве общего совета обычно лучше избегать null s как можно больше утечки в коде Scala.

...