Как использовать функциональный интерфейс внутри класса .kt - PullRequest
1 голос
/ 01 апреля 2019

Я хотел бы использовать некоторые функциональные интерфейсы внутри пакета java.util.function, такие как DoubleBinaryOperator interface.

Я могу использовать его в Java, как показано ниже:

public enum Operation {
    PLUS("+", Double::sum),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final String symbol;
    private final DoubleBinaryOperator op;

    Operation(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

}

Но это не работает для меня в Kotlin, потому что Kotlin не может определить тип параметра.

enum class Operation private constructor(private val symbol: String, private val op: DoubleBinaryOperator) {
    PLUS("+", { x, y -> x + y }),
    MINUS("-", { x, y -> x - y }),
    TIMES("*", { x, y -> x * y }),
    DIVIDE("/", { x, y -> x / y });

}

1 Ответ

1 голос
/ 01 апреля 2019

Вы можете достичь желаемого (преобразование SAM) с помощью следующего синтаксиса:

enum class Operation private constructor(private val symbol: String, private val op: DoubleBinaryOperator) {
    PLUS("+", DoubleBinaryOperator { left, right -> left + right }),
    ...
}

Обратите внимание, что это работает только для реализации интерфейсов Java, как описано здесь .

EDIT

Чтобы расширить мой комментарий ниже, вместо функциональных интерфейсов можно использовать лямбды Kotlin (так называемое преобразование SAM) только при вызове кода Java из Kotlin. Это не разрешено в чистом Kotlin, так как вы можете использовать типы функций (например, (Double, Double) -> Double, для имитации DoubleBinaryOperator).

В качестве примера рассмотрим следующий класс Java:

public class MyClass {
    String append(String input, Supplier<String> supplier) {
        return input.concat(supplier.get());
    }
}

В Kotlin вы можете использовать его так:

val myClass = MyClass()

// Use case 1
myClass.append("something") {
    "suffix"
}

// Use case 2
myClass.append("Something", Supplier { "suffix" })

Обратите внимание, что моя IDE говорит мне, что есть "избыточный SAM-конструктор" для варианта использования 2.

Теперь давайте перепишем MyClass на Kotlin:

class MyClass {
    fun append(input: String, supplier: Supplier<String>): String {
        return input + supplier.get()
    }
}

Если мы не изменим код, использующий его, мы получим ошибку компиляции для варианта использования 1: «Требуется поставщик, найдено () -> строка» (это та же проблема, что и у вас), поскольку преобразование SAM не может быть сделано Однако вы можете «форсировать» его, используя конструкторы SAM (то есть вариант использования 2).

...