Scala реализация интерфейса одного метода
Имеет ли Scala какой-либо синтаксический сахар для замены следующего кода:
val thread = new Thread(new Runnable {
def run() {
println("hello world")
}
})
с чем-то более похожим:
val thread = new Thread(() => println("hello world"))
в случаях, когда для свойства/интерфейса требуется только один метод для реализации? Если нет, есть ли шанс получить эту функцию в Scala в будущем? Это особенно полезно, когда речь идет о Java-классах.
Я нашел аналогичный вопрос, заданный три года назад: В целом реализация интерфейса Java Single-Abstract-Method с закрытием Scala? В ответе говорится, что мы должны иметь функция в Scala 2.10. Я искал ключевое слово Single Abstract Method, но ничего не нашел. Что случилось с этой функцией?
Ответы
Ответ 1
Scala имеет экспериментальную поддержку для SAM, начиная с 2.11, под флагом -Xexperimental
:
Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :set -Xexperimental
scala> val r: Runnable = () => println("hello world")
r: Runnable = [email protected]
scala> new Thread(r).run
hello world
Изменить. Начиная с версии 2.11.5 это также можно сделать inline:
scala> new Thread(() => println("hello world")).run
hello world
Также применяются обычные ограничения на ожидаемый тип:
- он должен определить один абстрактный метод,
- его основной конструктор (если он есть) должен быть общедоступным, no-args, а не перегружен,
- абстрактный метод должен принимать один список аргументов,
- абстрактный метод должен быть мономорфным.
В соответствии с оригинальной фиксацией Adriaan, некоторые из этих ограничений могут быть отменены в будущем, особенно последние два.
Ответ 2
При выполнении этого в общем случае, безусловно, сложно, если вы обнаружили, что вам действительно нужно это только для некоторых определенных типов Java, тогда несколько простых неявных преобразований могут хорошо выполнять работу. Например:
val thread = new Thread(() => println("hello world"))
thread.start
implicit def function0ToRunnable(f:() => Unit):Runnable =
new Runnable{def run() = f()}
Иногда попытка решить проблему общим и полностью повторно используемым способом - это неправильный подход, если ваша фактическая проблема более ограничена, чем вы думаете.
Ответ 3
Типы SAM поддерживаются с помощью invokeDynamic, так как scala-2.12 похож на JDK-8, ниже был протестирован на 2.12.3. Замечания о выпуске SAM можно найти здесь - http://www.scala-lang.org/news/2.12.0/
object ThreadApp extends App {
println("Main thread - begins")
val runnable: Runnable = () => println("hello world - from first thread")
val thread = new Thread(runnable)
println("Main thread - spins first thread")
thread.start()
val thread2 = new Thread(() => println("hello world - from second thread"))
println("Main thread - spins second thread")
thread2.start
thread.join()
thread2.join()
println("Main thread - end")
}