我想为List实现一个累计求和的方法。此函数应接受List、List等类型。我可以说它应该接受任何实现add方法的List类型,但我在官方文档中找不到指定这一点的方法。我尝试使用Number类型,但显然不起作用。如何制作一个泛型扩展函数来接受任何实现特定方法(如add)的类型?
数字只有以下方法:
public abstract fun toDouble(): Double
public abstract fun toFloat(): Float
public abstract fun toLong(): Long
public abstract fun toInt(): Int
public abstract fun toChar(): Char
public abstract fun toShort(): Short
public abstract fun toByte(): Byte
由于没有add方法,因此无法将它们相加。
typealias Adder<T> = (T)->T
fun <T: Number> T.toAdder(): Adder<T> {
return when(this) {
is Long -> {{it -> (this as Long + it as Long) as T}}
is Int -> {{it -> (this as Int + it as Int) as T}}
is Double -> {{it -> (this as Double + it as Double) as T}}
else -> throw AssertionError()
}
}
fun <T: Number> List<T>.mySum(zero: T): T {
return map { it.toAdder() }.fold(zero) { acc, func -> func(acc) }
}
fun main(args: Array<String>) {
val total = listOf(1,2,4).mySum(0)
}
这个方法可以运行,但是需要进行大量的类型转换,应该避免使用
fun Iterable<Byte>.sum(): Int { /* compiled code */ }
fun Iterable<Double>.sum(): Double { /* compiled code */ }
fun Iterable<Float>.sum(): Float { /* compiled code */ }
fun Iterable<Int>.sum(): Int { /* compiled code */ }
fun Iterable<Long>.sum(): Long { /* compiled code */ }
fun Iterable<Short>.sum(): Int { /* compiled code */ }
inline fun <T> Iterable<T>.sumBy(selector: (T) -> Int): Int { /* compiled code */ }
inline fun <T> Iterable<T>.sumByDouble(selector: (T) -> Double): Double { /* compiled code */ }
从中可以看出,没有办法为“具有plus
方法的类型列表”编写函数,因为Kotlin不是鸭子类型。
此外,您提到了List<实现add的任何内容>
,这是不清楚的(或者说是清楚但不正确的),因为在Kotlin中,所有数字类型都有plus
而不是add
。由此可以知道,不同的类对“add”操作有自己的定义,并且在不同情况下该操作具有不同的名称。
我建议您使用名为reduce
、reduceRight
、fold
或foldRight
的函数,通过传递参数来自定义您的“add”操作。
例如,List<Int>
的sum
实现基本上是:
fun List<Int>.sum() = fold(0, Int::plus)
等等类似的内容。
sum
方法,但累加和是另一回事。累加和是一个列表,其中第i
个元素是初始列表的前i
个元素之和。例如,1 3 5 2 1
的累加和为1 4 9 11 12
。
这就是我以这种方式提问的原因。抱歉,但这并没有真正回答我的问题:/ - Rares DimaNumber
的子类型之间重用代码,并以sum
的实现为例(证明我所说的是正确的),但你说这并没有回答你的问题。我猜你是在问累加和的实现,这被认为是SO上的垃圾信息。 - ice1000interface Adder<T> {
fun add(x: T, y: T): T
}
object IntAdder : Adder<Int> {
fun add(x: Int, y: Int): Int = x + y
}
// similar for other types
// definition of cumulativeSum
fun <T> cumulativeSum(list: List<T>, adder: Adder<T>): List<T> = ...
// call
cumulativeSum(listOf(1,2,3), IntAdder)
类型类解决的问题是您不需要手动传递adder
参数,而是编译器会根据T
来确定它。