MST

星途 面试题库

面试题:Kotlin类型推断与类型提升在泛型中的交互

编写一个Kotlin泛型函数,该函数接收一个`List`参数,其中`List`的元素类型是一个数字类型(`Number`的子类),函数返回这些元素的平均值。要求利用类型推断和类型提升来正确实现这个函数,同时解释在泛型环境下类型推断和类型提升是如何协同工作的,以及可能会遇到哪些潜在的问题及解决方案。
40.2万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

Kotlin代码实现

fun <T : Number> calculateAverage(list: List<T>): Double {
    return list.sumOf { it.toDouble() } / list.size
}

类型推断和类型提升的协同工作

  1. 类型推断:在Kotlin中,类型推断是指编译器可以根据上下文自动推断出变量或函数参数的类型。在上述代码中,<T : Number> 声明了泛型类型 TNumber 的子类。当调用 calculateAverage 函数时,编译器会根据传入的 List 的实际元素类型来推断 T 的具体类型。例如,如果传入 List<Int>,那么 T 就被推断为 Int
  2. 类型提升:类型提升是指将不同类型的数字提升到一个共同的类型以便进行运算。在上述代码中,sumOf 函数对 List 中的元素求和,但是由于 List 的元素类型是 TNumber 的子类),不同的 Number 子类(如 IntDoubleFloat 等)不能直接进行求和运算。因此,通过 it.toDouble() 将每个元素提升为 Double 类型,这样所有元素就有了共同的类型 Double,可以进行求和运算,最后再除以 list.size(也是 Int 类型,会被提升为 Double)得到平均值。

潜在问题及解决方案

  1. 空列表问题:如果传入一个空列表,代码会抛出 ArithmeticException 异常,因为除以0是不允许的。解决方案是在函数开始处添加对空列表的检查:
fun <T : Number> calculateAverage(list: List<T>): Double {
    if (list.isEmpty()) {
        return 0.0
    }
    return list.sumOf { it.toDouble() } / list.size
}
  1. 精度问题:当 List 中的元素类型为 Float 时,由于 Float 精度有限,转换为 Double 可能会导致精度损失。如果需要更高精度的计算,可以考虑使用 BigDecimal 类。不过这样会使代码更复杂,需要处理 BigDecimal 的加法和除法运算。
import java.math.BigDecimal

fun <T : Number> calculateAverage(list: List<T>): BigDecimal {
    if (list.isEmpty()) {
        return BigDecimal.ZERO
    }
    val sum = list.fold(BigDecimal.ZERO) { acc, number -> acc + BigDecimal(number.toString()) }
    return sum / BigDecimal(list.size)
}

这样可以避免浮点数精度问题,但会增加运算的复杂性和性能开销。