Kotlin中如何使用泛型实现不同类型数值的相加
错误原因梳理
- 泛型无界导致编译不通过:定义的
<T, U>没有指定类型上界,T可以是任意类型,编译器无法确认T拥有可接收U类型参数的plus方法,直接调用a.plus(b)会触发编译错误。 - 自定义泛型
plus扩展完全无效:编写的operator fun <U> U.plus(b: U) {}存在核心缺陷:一是给所有类凭空添加了一个无实际计算逻辑、返回Unit的plus方法,既会污染所有类型的plus行为,还会和原生数值的plus运算符产生冲突;二是该扩展要求接收者类型和参数类型完全一致,传入Int类型接收者、搭配Double类型参数的调用根本无法匹配这个扩展。 - 对原生
plus声明的误解:看到的无函数体的plus定义,是Kotlin标准库为内置数值类型定义的编译期内置运算符——这些函数没有普通的JVM方法实现,编译时会直接被翻译为对应基本类型的加法字节码,不存在通用的、可适配所有泛型数值类型的plus接口。
正确实现思路
Kotlin的所有内置数值类型(Byte/Short/Int/Long/Float/Double)都实现了Number抽象类,我们可以通过给泛型加上Number上界,限定参数必须是数值类型,再根据精度需求选择合适的策略完成加法。
通用简洁实现(统一转Double兼容所有数值类型)
直接将两个数值参数统一转换为精度最高的Double类型完成计算,代码简洁,不存在类型匹配问题:
fun <T: Number, U: Number> add(a: T, b: U): Number { return a.toDouble() + b.toDouble() } fun main() { println(add(4, 5.6)) // 输出9.6 println(add(2L, 3)) // 输出5.0 println(add(1.toByte(), 2.5f)) // 输出3.5 }
智能精度适配实现(匹配最优返回类型)
如果不希望整数之间的加法返回带小数点的Double类型,可以通过类型判断,按精度优先的原则选择最合适的数值类型做计算:
fun <T: Number, U: Number> addSmart(a: T, b: U): Number { return when { // 任意参数是Long则统一转Long计算,避免整数溢出 a is Long || b is Long -> a.toLong() + b.toLong() // 任意参数是Int则转Int计算 a is Int || b is Int -> a.toInt() + b.toInt() // 只要存在浮点类型则统一转Double计算保证精度 else -> a.toDouble() + b.toDouble() } } fun main() { println(addSmart(4, 5.6)) // 输出9.6 (Double) println(addSmart(100, 200)) // 输出300 (Int) println(addSmart(1000, 2000L)) // 输出3000 (Long) }
注:由于Kotlin的Number抽象类本身没有定义跨类型的加法接口,无法在不做类型判断的前提下实现完全静态的、和原生运算符精度完全一致的泛型加法,上述两种方案已经覆盖了绝大多数跨数值类型加法的使用场景。
内容的提问来源于stack exchange,提问作者Mirel
相关产品推荐
相关产品推荐

