Как kotlin делает setOnClickListener принимать функции как параметр

В kotlin мы можем использовать setOnClickListener() следующим образом:

 view.setOnClickListener { println("Hello") } 

Но если я определяю свой собственный интерфейс, я могу передать анонимный объект следующим образом:

 obj.setMyListener(object: MyListener() { ... }) 

Мне просто интересно, как они делают setOnClickListener() принимают функцию, а не анонимный объект.

Согласно документации Kotlin о взаимодействии Java , для функционального интерфейса, определенного на Java, вы можете использовать преобразование SAM.

Как и Java 8, Kotlin поддерживает конверсии SAM. Это означает, что литералы функции Kotlin могут быть автоматически преобразованы в реализации интерфейсов Java с помощью одного метода, отличного от метода по умолчанию, если типы параметров метода интерфейса соответствуют типам параметров функции Kotlin.

 val runnable = Runnable { println("This runs in a runnable") } val executor = ThreadPoolExecutor() // Java signature: void execute(Runnable command) executor.execute { println("This runs in a thread pool") } 

Тем не менее, Kotlin имеет функциональные типы, поэтому преобразование SAM не работает для интерфейсов, определенных в Kotlin:

Также обратите внимание, что эта функция работает только для Java interop; поскольку Kotlin имеет собственные типы функций, автоматическое преобразование функций в реализации интерфейсов Kotlin не является необходимым и поэтому не поддерживается.


Возможные решения:

  1. Определите интерфейс в Java. Полезно, если это библиотека / код, который может использоваться из Java-кода.
  2. Чтобы метод получил функцию в качестве аргумента:

     // Example listener receives a bool and return unit. fun setMyListener(listener: (isChecked: Bool) -> Unit) { ... } // Usage: obj.setMyListener { isChecked -> } 
  3. Использовать псевдоним типа (поддерживается только в Kotlin 1.1+):

     typealias MyListener = (Bool) -> Unit fun setMyListener(listener: MyListener) { ... }