Passando uma função Scala para um método Java 8


18

O código Scala a seguir funciona e pode ser passado para um método Java esperando uma função. Existe uma maneira mais limpa de fazer isso? Aqui está o meu primeiro passe:

val plusOne = new java.util.function.Function[Int,Int] {
  override def apply(t:Int):Int = t + 1

  override def andThen[V](after:function.Function[_ >: Int, _ <: V]):
    function.Function[Int, V] = ???

  override def compose[V](before:function.Function[_ >: V, _ <: Int]):
    function.Function[V, Int] = ???
}

Aqui está minha segunda passagem - ele usa um wrapper genérico para a interface Java-8 Function para tornar a sintaxe do Scala mais simples:

// Note: Function1 is Scala's functional interface,
// Function (without the 1) is Java 8's.
case class JavaFunction1[U,V](f:Function1[U,V]) extends Function[U,V] {
  override def apply(t: U): V = f(t)
  override def compose[T](before:Function[_ >: T, _ <: U]):
    Function[T, V] = ???
  override def andThen[W](after:Function[_ >: V, _ <: W]):
    Function[U, W] = ???
}

val plusOne = JavaFunction1((x:Int) => x + 1)
val minusOne = JavaFunction1((x:Int) => x - 1)

Podemos fazer melhor?

Como acompanhamento, existe alguma chance de o Scala algum dia usar o código operacional dinâmico de invocação, como o Java 8 faz para seu aplicativo de função de primeira classe? Isso fará com que tudo funcione magicamente ou ainda precisará haver uma conversão sintática?

Respostas:


10

Você pode tornar a conversão implícita:

implicit def toJavaFunction[U, V](f:Function1[U,V]): Function[U, V] = new Function[U, V] {
  override def apply(t: U): V = f(t)

  override def compose[T](before:Function[_ >: T, _ <: U]):
    Function[T, V] = toJavaFunction(f.compose(x => before.apply(x)))

  override def andThen[W](after:Function[_ >: V, _ <: W]):
    Function[U, W] = toJavaFunction(f.andThen(x => after.apply(x)))
}

implicit def fromJavaFunction[U, V](f:Function[U,V]): Function1[U, V] = f.apply

Você realmente não precisa substituir composee andThen, mas talvez o compilador Scala ainda não conheça os métodos de interface padrão do Java 8. (EDIT: deve funcionar em 2.10.3.)

Além disso, você deve poder atribuir lambdas do Scala (ou seja x => ...) a Functione quaisquer outros tipos de SAM no Scala 2.11 e Java 8 lambdas a Function1. (EDIT: isso realmente foi adicionado no Scala 2.12, não 2.11.)


you should be able to assign Scala lambdas- Isso significa que, no Scala 2.11, uma função Scala pode ser passada como argumento para um Java8 Lambda?
Kevin Meredith

A possibilidade de passar como argumento depende do tipo de lambda; se for por exemplo java.util.function.Consumer[scala.Function1[Integer, String]], também pode ser feito antes da versão 2.11.
Alexey Romanov
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.