Kotlin为Number类型函数实现嵌套infix扩展时类型不匹配问题
问题原因分析
为什么(Int) -> Int无法匹配(Number) -> Number
Kotlin的函数类型遵循形变规则:
- 函数入参类型是逆变的:如果
P1是P2的父类,那么(P2) -> R是(P1) -> R的父类 - 函数返回值类型是协变的:如果
R1是R2的子类,那么(P) -> R1是(P) -> R2的子类
对于(Int) -> Int和(Number) -> Number的匹配:
- 入参部分:
Int是Number的子类,所以(Int) -> *是(Number) -> *的父类,父类型无法直接赋值给子类型 - 即使返回值
Int是Number的子类符合协变规则,入参部分的逆变规则不满足,所以编译器会直接抛出类型不匹配错误
如果强行把(Int)->Int转为(Number)->Number,会存在类型安全风险:后者允许传入任意Number子类(比如Float、Long),但前者只能处理Int类型参数,运行时会抛出类型转换异常。
通用函数组合实现方案
使用泛型约束即可实现支持所有数字类型函数的nest中缀方法,同时保证类型安全:
class Entry { companion object { private fun f(x: Int) = x * 2 private fun g(x: Int) = x + 2 // 支持跨数字类型组合的示例函数 private fun longF(x: Long) = x.toDouble() / 2 private fun floatG(x: Float) = x.toLong() + 100L // 泛型nest实现,三个泛型分别对应组合后函数的入参、中间传递值、最终返回值 private infix fun <A: Number, B: Number, C: Number> ((B) -> C).nest(inner: (A) -> B): (A) -> C { return { x -> this(inner(x)) } } @JvmStatic fun main(args: Array<String>) { // 同类型Int函数组合 val intFunc = ::f nest ::g println(intFunc(10)) // 输出 24,逻辑和原始版本一致 // 跨数字类型组合:Float -> Long -> Double val mixedFunc = ::longF nest ::floatG println(mixedFunc(8.8f)) // 输出 54.0 } } }
如果你不需要限定只能组合数字类型的函数,可以去掉泛型的: Number上界,该方法就可以支持任意类型的函数嵌套组合。
内容的提问来源于stack exchange,提问作者Langua
相关产品推荐
相关产品推荐

