Как решить проблему лямбда / SAM в проектах мультиплатформенных библиотек Kotlin? - PullRequest
3 голосов
/ 11 июля 2019

У меня проблема с SAMs в Котлине.Я работаю над библиотекой, в которой есть функции, которые принимают лямбду.Моя проблема в том, что я не могу просто написать это:

fun myFun(someLambda: (A) -> B) {
    // ...
}

, потому что если пользователь Java хотел бы вызвать его, ему нужно было бы передать ему Function1, что не очень хороший UX.Если я вместо этого создаю SAM:

fun myFun(someSam: Function<A, B>) {
    // ...
}

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

inline fun <A, B> MyClass.someFun(crossinline fn: (A) -> B) {
    return someFun(object : Function<A, B> {
        override fun accept(value: A): B {
            return fn.invoke(value)
        }
    })
}

Этот метод поставляется смного шаблонного, и это также трудно поддерживать.Есть ли лучшая альтернатива для решения этой проблемы?

1 Ответ

0 голосов
/ 11 июля 2019

Я просто добавил вспомогательные функции, которые позволяли мне легко преобразовывать функциональные интерфейсы Java в их аналог Kotlin, но помещали их в галочки (что я не люблю видеть в обычном коде Kotlin (в отличие от тестов);-)), например:

fun <T> `$consume`(consumer: Consumer<T>): (T) -> Unit = consumer::accept
fun <T, R> `$`(func: java.util.function.Function<T, R>): (T) -> R = func::apply
fun <T, U, R> `$`(func: java.util.function.BiFunction<T, U, R>): (T, U) -> R = func::apply
// etc.

Предполагая, что в Kotlin имеются следующие функции:

fun doSomething1(c : (String) -> Unit) : String = TODO()
fun doSomething2(f : (String) -> String) : String = TODO()
fun doSomething3(f : (String, String) -> String) : String = TODO()

Использование из Java может выглядеть следующим образом:

doSomething1($consume((e) -> System.out.println(e)));
doSomething2($((e) -> e + "ok"));
doSomething3($((e1, e2) -> String.join(", ", e1, e2)));

Обратите внимание, что я использовал $consume, чтобы преодолеть неоднозначность относительно Function<T, R>.Вы также можете использовать $ для потребителя, но тогда вам понадобятся либо фигурные скобки, либо вам придется привести его к Consumer<T> -интерфейсу, чтобы использовать ссылки на методы, например:

doSomething1($((e) -> { System.out.println(e); }));
doSomething1($((Consumer<String>) System.out::println));

Основным преимуществом использования $ с обратными тиками является то, что в Kotlin вы, вероятно, не будете его использовать, поскольку его не так легко записать (кто начинает с обратных тиков при вызове функций?) И завершение кода.не предлагает это так просто.

Более того, $ -sign напрямую вызывается на стороне Java без проблем.

Может быть, вы хотите смешать свои функции перегрузки с этим, так что вы делаетене нужно реализовывать весь код перегрузки и помещать эти функции в свою собственную библиотеку, доступную для разработчиков Java?

...