Melewati fungsi Scala ke metode Java 8

18

Kode Scala berikut berfungsi dan dapat dikirimkan ke metode Java yang mengharapkan suatu fungsi. Apakah ada cara yang lebih bersih untuk melakukan ini? Ini kartu masuk pertamaku:

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] = ???
}

Inilah pass kedua saya - ini menggunakan pembungkus generik untuk antarmuka Fungsi Java-8 untuk membuat sintaks Scala lebih sederhana:

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

Bisakah kita berbuat lebih baik?

Sebagai tindak lanjut, apakah ada kemungkinan Scala suatu hari nanti akan menggunakan op-code invoke-dynamic seperti yang dilakukan Java 8 untuk aplikasi fungsi kelasnya? Apakah itu akan membuat semuanya bekerja secara ajaib, atau apakah masih perlu ada konversi sintaksis?

GlenPeterson
sumber

Jawaban:

10

Anda dapat membuat konversi tersirat:

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

Anda seharusnya tidak perlu menimpa composedan andThen, tapi mungkin kompiler Scala belum tahu tentang metode antarmuka standar Java 8. (EDIT: itu harus bekerja di 2.10.3.)

Selain itu, Anda harus dapat menetapkan Scala lambdas (yaitu x => ...) ke Functiondan semua jenis SAM lainnya di Scala 2.11, dan Java 8 lambdas Function1. (EDIT: ini sebenarnya ditambahkan di Scala 2.12, bukan 2.11.)

Alexey Romanov
sumber
you should be able to assign Scala lambdas- Ini berarti bahwa, dalam Scala 2.11, fungsi Scala dapat dilewatkan sebagai argumen untuk Java8 Lambda?
Kevin Meredith
Apakah dapat dilewati sebagai argumen tergantung pada jenis lambda; jika itu eg java.util.function.Consumer[scala.Function1[Integer, String]]maka itu bisa dilakukan sebelum 2.11 juga.
Alexey Romanov