如何编写支持所有Number类型的Kotlin泛型扩展方法?
Kotlin泛型处理数字类型的最优实现方案
问题分析
你提供的泛型代码无法编译,核心原因是**Number类本身没有定义乘法运算符(*)**。虽然Int、Double等数字子类都重载了*,但编译器在处理泛型T : Number时,无法确定具体的子类类型,因此无法解析it * it的操作。
你提到的两种方案都有明显缺陷:转Double会丢失原类型信息,单独写方法则导致代码冗余。结合Kotlin扩展方法编译期解析的特性,以下是更优的实现方式。
最优方案:inline + reified泛型函数
利用Kotlin的inline和reified特性,在编译期确定具体的数字类型,执行对应类型的乘法操作,同时保持返回类型与输入一致。
实现代码
inline fun <reified T : Number> Array<T>.pow2(): List<T> { return map { number -> when (number) { is Int -> (number * number) as T is Double -> (number * number) as T is Long -> (number * number) as T is Float -> (number * number) as T is Short -> (number * number) as T is Byte -> (number * number) as T else -> throw IllegalArgumentException("不支持的数字类型: ${number::class.simpleName}") } } } fun main() { val ints = arrayOf(1, 2, 3) println(ints.pow2()) // 输出: [1, 4, 9] val doubles = arrayOf(1.0, 2.0, 3.0) println(doubles.pow2()) // 输出: [1.0, 4.0, 9.0] val longs = arrayOf(1L, 2L, 3L) println(longs.pow2()) // 输出: [1, 4, 9] }
方案优势
- 编译期解析:
reified类型参数让编译器在编译期就能获取具体的T类型,避免运行期类型检查开销,符合Kotlin扩展方法的设计特性。 - 类型安全:返回类型与输入数组的类型完全一致,不会像转
Double那样丢失类型信息。 - 代码简洁:无需为每种数字类型单独编写重复方法,所有逻辑集中在一个泛型函数中。
代码优化(可选)
如果需要更清晰的代码结构,可以将类型判断逻辑抽离为扩展函数:
inline fun <reified T : Number> Array<T>.pow2(): List<T> { fun Number.square(): T = when (this) { is Int -> (this * this) as T is Double -> (this * this) as T is Long -> (this * this) as T is Float -> (this * this) as T is Short -> (this * this) as T is Byte -> (this * this) as T else -> throw IllegalArgumentException("不支持的数字类型: ${this::class.simpleName}") } return map { it.square() } }
补充说明
Kotlin不允许直接为内置数字类型(如Int、Double)添加自定义接口实现,因此无法通过接口多态的方式直接让泛型T支持乘法操作。而inline + reified的方案恰好规避了这个限制,同时满足编译期解析的要求。
内容的提问来源于stack exchange,提问作者Alex Craft
相关产品推荐
相关产品推荐

