具有高阶函数的 Kotlin 合约
Kotlin contract with high order functions
我对 Kotlin 的可空性有疑问,我想知道我能否通过合同解决它。
对于这样的 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
时执行action参数,所以它看起来像下面:
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
不会使用 null 参数执行?
所有类型参数在没有限制的情况下默认为 nullable(换句话说,它们派生自 Any?
)。解决这个问题的简单方法就是在类型参数上指定非空绑定:<T : Any>
我已经创建了 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)
}
这个想法可能会帮助遇到类似问题的人,但它不符合我的期望,我仍然指望基于高阶函数的解决方案。
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 }
}
作为旁注,参数是 "wrong way around" for map
;此类函数通常称为 contramap
.
我对 Kotlin 的可空性有疑问,我想知道我能否通过合同解决它。
对于这样的 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
时执行action参数,所以它看起来像下面:
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
不会使用 null 参数执行?
所有类型参数在没有限制的情况下默认为 nullable(换句话说,它们派生自 Any?
)。解决这个问题的简单方法就是在类型参数上指定非空绑定:<T : Any>
我已经创建了 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)
}
这个想法可能会帮助遇到类似问题的人,但它不符合我的期望,我仍然指望基于高阶函数的解决方案。
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 }
}
作为旁注,参数是 "wrong way around" for map
;此类函数通常称为 contramap
.