面试题答案
一键面试Kotlin代码实现
fun <T : Number> calculateAverage(list: List<T>): Double {
return list.sumOf { it.toDouble() } / list.size
}
类型推断和类型提升的协同工作
- 类型推断:在Kotlin中,类型推断是指编译器可以根据上下文自动推断出变量或函数参数的类型。在上述代码中,
<T : Number>
声明了泛型类型T
是Number
的子类。当调用calculateAverage
函数时,编译器会根据传入的List
的实际元素类型来推断T
的具体类型。例如,如果传入List<Int>
,那么T
就被推断为Int
。 - 类型提升:类型提升是指将不同类型的数字提升到一个共同的类型以便进行运算。在上述代码中,
sumOf
函数对List
中的元素求和,但是由于List
的元素类型是T
(Number
的子类),不同的Number
子类(如Int
、Double
、Float
等)不能直接进行求和运算。因此,通过it.toDouble()
将每个元素提升为Double
类型,这样所有元素就有了共同的类型Double
,可以进行求和运算,最后再除以list.size
(也是Int
类型,会被提升为Double
)得到平均值。
潜在问题及解决方案
- 空列表问题:如果传入一个空列表,代码会抛出
ArithmeticException
异常,因为除以0是不允许的。解决方案是在函数开始处添加对空列表的检查:
fun <T : Number> calculateAverage(list: List<T>): Double {
if (list.isEmpty()) {
return 0.0
}
return list.sumOf { it.toDouble() } / list.size
}
- 精度问题:当
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)
}
这样可以避免浮点数精度问题,但会增加运算的复杂性和性能开销。