Реализация интерфейса единого метода 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, но ничего не нашел. Что случилось с функцией?


person Mequrel    schedule 02.04.2014    source источник
comment
У меня есть небольшая демонстрация на основе макросов здесь. Его легко можно было бы сделать более общим и надежным, но вы не получите той краткости, о которой спрашиваете.   -  person Travis Brown    schedule 02.04.2014


Ответы (3)


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 = $anonfun$1@7861ff33

scala> new Thread(r).run
hello world

Изменить. Начиная с версии 2.11.5 это также можно сделать встроенным:

scala> new Thread(() => println("hello world")).run
hello world

Также применяются обычные ограничения относительно ожидаемого типа:

  • он должен определять один абстрактный метод,
  • его основной конструктор (если есть) должен быть общедоступным, без аргументов, не перегруженным,
  • абстрактный метод должен принимать один список аргументов,
  • абстрактный метод должен быть мономорфным.

Согласно исходному коммиту Адриана, некоторые из этих ограничений могут быть сняты в будущем. особенно последние два.

person gourlaysama    schedule 02.04.2014
comment
Обратите внимание, что проблема была исправлена. - person som-snytt; 25.02.2015

Типы SAM поддерживаются с помощью invokeDynamic, начиная с scala-2.12, похожего на JDK-8. Ниже было протестировано на 2.12.3. Примечания к выпуску SAM можно найти здесь — http://www.scala-lang.org/новости/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")
}
person Mohan Narayanaswamy    schedule 04.03.2018

Хотя сделать это общим способом, безусловно, сложно, если вы обнаружите, что это действительно нужно только для нескольких определенных типов Java, то несколько простых неявных преобразований могут прекрасно справиться с этой задачей. Например:

val thread = new Thread(() => println("hello world"))
thread.start

implicit def function0ToRunnable(f:() => Unit):Runnable = 
  new Runnable{def run() = f()}

Иногда попытка решить проблему общим и полностью пригодным для повторного использования способом является неправильным подходом, если ваша реальная проблема более ограничена, чем вы думаете.

person cmbaxter    schedule 02.04.2014