Я работаю над многоплатформенным проектом и пытаюсь предоставить API для добавления слушателей:
interface InputEmitter {
fun addInputListener(listener: InputListener)
}
InputListener
— это SAM-интерфейс и выглядит он так:
interface InputListener {
fun onInput(input: Input)
}
Моя проблема в том, что это правильно работает как с Java, так и с Kotlin, но на стороне Kotlin это не идиоматично, так как я должен вызывать его следующим образом:
obj.addInputListener(object : InputListener {
override fun onInput(input: Input) {
TODO("not implemented")
}
})
вместо этого:
obj.addInputListener {
TODO("not implemented")
}
В этом случае компилятор жалуется на несоответствие типов, что нормально.
Я мог бы решить эту проблему, используя аннотацию @FunctionalInterface
, и в этом случае сторона Kotlin была бы лучше, но, поскольку это мультиплатформенный проект, я не могу использовать эту аннотацию.
Добавление двух функций:
fun addInputListener(listener: InputListener)
fun addInputListener(listener: (Input) -> Unit)
также не работает, потому что это неоднозначно со стороны Java. Как я могу решить эту проблему, чтобы она идиоматически работала как с Java, так и с Kotlin?
Я знаю, что могу сделать что-то вроде этого:
fun addInputListener(listener: InputListener)
fun onInput(listener: (Input) -> Unit)
но в этом случае пользователь Java будет озадачен, когда он/она захочет использовать вариант onInput
(поскольку он разрешается в Function1
, который не может быть создан со стороны Java).
Есть ли каноническое решение этой проблемы?
@FunctionalInterface
? Kotlin не поддерживает SAM для интерфейсов, определенных Kotlin, независимо от того, как они аннотированы. - person yole   schedule 25.09.2018interface
с аннотацией, а затем использовать ее так:addInputListener(InputListener{ // do something })
, которая все еще не идеальна, но лучше, чем альтернатива. - person Adam Arold   schedule 25.09.2018addInputListener
: одна, которую вы видите выше, и другая, которая является функцией расширения и принимает лямбда. Есть ли лучшее решение? - person Adam Arold   schedule 25.09.2018Function1
можно реализовать и на Java, даже с лямбдой, это просто довольно уродливый API, и есть причуды, например, может потребоваться вернутьUnit.INSTANCE
для функции-> Unit
. Interop на данный момент просто уродлив, и ваш способ использования функций расширения уже лучше, чем то, что я нашел до сих пор. Связанный: youtrack.jetbrains.com/issue/KT-7770 обсуждает добавление преобразования sam для родные интерфейсы kotlin, но если это произойдет, то не в ближайшее время. - person zapl   schedule 25.09.2018