You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin泛型乘法兼容问题:如何适配Int/Float/Long/Double

解决泛型数字乘积函数的实现问题

因为Kotlin的Number是抽象基类,并没有定义加减乘除等运算方法,所以直接用<T: Number>约束无法直接进行acc * number这类操作。下面提供几种可行的实现方案:

方案一:基于类型判断的直接实现

这种方法通过判断列表中元素的具体类型,转换为对应类型后执行乘积运算,最后转回泛型类型。适合元素类型统一的场景:

private fun <T : Number> productNumbers(listOfNumbers: List<T>, ignoreIndex: Int): T {
    return when (val first = listOfNumbers.firstOrNull()) {
        is Int -> listOfNumbers
            .filterIndexed { idx, _ -> idx != ignoreIndex }
            .map { it as Int }
            .fold(1) { acc, num -> acc * num } as T
        is Float -> listOfNumbers
            .filterIndexed { idx, _ -> idx != ignoreIndex }
            .map { it as Float }
            .fold(1f) { acc, num -> acc * num } as T
        is Long -> listOfNumbers
            .filterIndexed { idx, _ -> idx != ignoreIndex }
            .map { it as Long }
            .fold(1L) { acc, num -> acc * num } as T
        is Double -> listOfNumbers
            .filterIndexed { idx, _ -> idx != ignoreIndex }
            .map { it as Double }
            .fold(1.0) { acc, num -> acc * num } as T
        else -> throw IllegalArgumentException("不支持的数字类型: ${first?.javaClass?.simpleName}")
    }
}

方案二:使用内联泛型+具体化类型(更可靠)

利用Kotlin的reified关键字在编译期获取泛型类型信息,无需依赖列表第一个元素判断类型,类型安全性更高:

inline fun <reified T : Number> productNumbers(listOfNumbers: List<T>, ignoreIndex: Int): T {
    val initialValue = when (T::class) {
        Int::class -> 1 as T
        Float::class -> 1f as T
        Long::class -> 1L as T
        Double::class -> 1.0 as T
        else -> throw IllegalArgumentException("不支持的数字类型: ${T::class.simpleName}")
    }

    return listOfNumbers.foldIndexed(initialValue) { index, acc, num ->
        if (index != ignoreIndex) {
            when (T::class) {
                Int::class -> (acc as Int * num as Int) as T
                Float::class -> (acc as Float * num as Float) as T
                Long::class -> (acc as Long * num as Long) as T
                Double::class -> (acc as Double * num as Double) as T
                else -> throw IllegalArgumentException("不支持的数字类型")
            }
        } else {
            acc
        }
    }
}

方案三:定义运算接口扩展(面向对象风格)

先定义一个支持乘法的接口,再给各数字类型扩展实现该接口,最后基于接口约束实现泛型函数:

// 定义乘法运算接口
interface Multipliable<T> {
    fun multiply(other: T): T
}

// 给各数字类型扩展实现乘法接口
fun Int.multiply(other: Int): Int = this * other
fun Float.multiply(other: Float): Float = this * other
fun Long.multiply(other: Long): Long = this * other
fun Double.multiply(other: Double): Double = this * other

// 泛型函数实现
private fun <T : Number> productNumbers(listOfNumbers: List<T>, ignoreIndex: Int): T {
    val initialValue = when (listOfNumbers.firstOrNull()) {
        is Int -> 1 as T
        is Float -> 1f as T
        is Long -> 1L as T
        is Double -> 1.0 as T
        else -> throw IllegalArgumentException("不支持的数字类型")
    }

    return listOfNumbers.foldIndexed(initialValue) { index, acc, num ->
        if (index != ignoreIndex) {
            when (acc) {
                is Int -> acc.multiply(num as Int) as T
                is Float -> acc.multiply(num as Float) as T
                is Long -> acc.multiply(num as Long) as T
                is Double -> acc.multiply(num as Double) as T
                else -> throw IllegalArgumentException("不支持的数字类型")
            }
        } else {
            acc
        }
    }
}

注意事项

  • 以上方案均假设输入列表中的元素类型统一,若存在混合类型的场景,需要额外处理类型兼容问题
  • 原代码中1 as T的写法会导致类型转换异常(比如T为Float时,Int无法直接转Float),所以必须根据具体类型提供对应初始值

内容的提问来源于stack exchange,提问作者ant2009

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:15:07