与高阶函数科特林合同

问题描述 投票:1回答:3

我有科特林为空的问题,我不知道我能够用合同来解决它。对于这样的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)
}

所以,现在,有没有使用科特林合同,以确保编译器action不会与空参数执行任何选项?

generics kotlin kotlin-contracts
3个回答
1
投票

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
投票

所有类型的参数作为出厂默认为空的,如果无限的(换句话说,它们是从Any?派生)。解决这个简单的方法就是指定绑定在类型参数非空:<T : Any>


0
投票

我创建了专用于如下这种用法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)
}

这种想法可以帮助类似问题的人,但它不适合我的期望,我基于高阶函数的解决方案仍算。

热门问题
推荐问题
最新问题