Котлин контракт с функциями высокого порядка - PullRequest
0 голосов
/ 28 ноября 2018

У меня проблема с обнуляемостью Котлина, и мне интересно, могу ли я решить ее с помощью контрактов.Для такого Java интерфейса: interface Action<T>{ void execute(T param); } есть два расширения:

fun <T, R> Action<T>.map(mapper:(R)->T): Action<R> {
   return Action{ execute(mapper(it)) }
}

и

fun <T> Action<T>.ifNotNull(): Action<T> {
  return Action { if(it != null) execute(it) }
} 

Существует также общая модель с обнуляемыми данными:

class Model<T>(val data: T?)

Теперь я создал функцию, которая принимает Action интерфейс в качестве аргумента.Дело в том, что аргумент действия следует выполнять только тогда, когда param != null, поэтому он выглядит следующим образом:

fun <T> callback(model: Model<T>, action: Action<T>){
    action
    .map{ it.getData() } //compilation error: getData return T? when action require T
    .ifNotNull() //execute only when data!=null
    .execute(model)
}

Итак, есть ли возможность использовать контракт Kotlin, чтобы компилятор не выполнял action с нулемпараметр

Ответы [ 3 ]

0 голосов
/ 29 ноября 2018

Я создал Action реализацию интерфейса, предназначенную для этого использования, как показано ниже:

class ModelAction<T>(val action: Action<T>) : Action<T?> {
    override fun execute(param: T?) {
        param?.let {
            action.execute(it)
        }
    }
}

fun callback<T>(model: Model<T>, action: Action<T>){
    ModelAction(action)
    .map{ it.getData() } 
    .execute(model)
}

Эта идея может помочь кому-то с подобной проблемой, но она не соответствует моим ожиданиям, и я все еще рассчитываю на решениена основе функции высшего порядка.

0 голосов
/ 29 ноября 2018

ModelAction в вашем собственном ответе просто предоставляет правильную подпись для ifNotNull():

fun <T> Action<T>.ifNotNull(): Action<T?> {
    return Action { if(it != null) execute(it) }
} 

Тогда у вас неправильный порядок операций:

fun <T> callback(model: Model<T>, action: Action<T>){
    action
    .ifNotNull() // Action<T?>
    .map { model: Model<T> -> model.data } // Action<Model<T>>
    .execute(model)
}

Примечаниечто компилятор не сможет вывести R для этого map использования.Вы также можете написать это как

fun <T> modelAction(action: Action<T>): Action<Model<T>> {
    return action
    .ifNotNull()
    .map { it.data }
}

В качестве примечания, аргумент является "неправильным путем" для map;такие функции чаще называют contramap.

0 голосов
/ 28 ноября 2018

Все параметры типа поставляются как обнуляемые по умолчанию, если они не ограничены (другими словами, они получены из Any?).Простой способ исправить это - просто указать ненулевую границу для параметра типа: <T : Any>

...