Passer une fonction Scala à une méthode Java 8


18

Le code Scala suivant fonctionne et peut être transmis à une méthode Java qui attend une fonction. Existe-t-il une façon plus propre de procéder? Voici ma première 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] = ???
}

Voici mon deuxième passage - il utilise un wrapper générique pour l'interface de fonction Java-8 pour simplifier la syntaxe Scala:

// 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)

Pouvons-nous faire mieux?

À titre de suivi, y a-t-il une chance que Scala utilise un jour le code d'opération dynamique d'invocation comme Java 8 le fait pour son application de fonction de première classe? Est-ce que tout fonctionnera comme par magie, ou faudra-t-il encore une conversion syntaxique?

Réponses:


10

Vous pouvez rendre la conversion implicite:

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

Vous ne devriez pas avoir besoin de remplacer composeet andThen, mais peut-être que le compilateur Scala ne connaît pas encore les méthodes d'interface par défaut de Java 8. (EDIT: cela devrait fonctionner en 2.10.3.)

En outre, vous devriez pouvoir attribuer des lambdas Scala (c'est x => ...-à- dire ) à Functionet tout autre type SAM dans Scala 2.11, et des lambdas Java 8 à Function1. (EDIT: cela a en fait été ajouté dans Scala 2.12, pas 2.11.)


you should be able to assign Scala lambdas- Cela signifie que, dans Scala 2.11, une fonction Scala peut être passée comme argument pour un Lambda Java8?
— Kevin Meredith

La possibilité de le passer comme argument dépend du type de lambda; si c'est par exemple, java.util.function.Consumer[scala.Function1[Integer, String]]cela peut être fait avant 2.11 aussi.
— Alexey Romanov
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.