Kotlin通用数联盟?

Kotlin generic number Union?

我想为List实现一个累加法,这样的函数应该接受List<Int>List<Float>

我可以说它应该接受 List<anything that implements add>

但我看不到在官方文档中对此进行说明的方式。

我试过使用 Number 类型,但它显然不起作用。

我应该如何制作一个通用扩展函数来接受任何实现特定方法的类型,例如 add

在 Kotlin 中,stdlib 中有这些扩展函数:

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 */ }

从那里你可以看到没有办法为“List 具有 plus 方法的类型”编写函数,因为 Kotlin 不是鸭子类型的。

此外,您提到的 List<anything that implements add> 不清楚(或者,清楚但不正确),因为在 Kotlin 中,所有数字类型都有 plus 而不是 add。由此可见,不同的类对"add"操作有自己的定义,这种操作在不同的情况下有不同的名称。

我建议您使用名为 reduce、或 reduceRight、或 fold、或 foldRight 的功能,它允许您自定义 "add" 通过传递参数进行操作。

像,sumList<Int>的实现基本上是:

fun List<Int>.sum() = fold(0, Int::plus)

等等。

为什么你不能添加数字

号码只有以下方法:

  • 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

没有加法,不能加在一起

解决方法

  • 您可以使用 Iterable 方法,它应该在列表中可用
  • 您可以包装数字,并让包装器提供添加方法
  • 你可以使用反射来做到这一点,但这可能不是最好的方法

Hacky 转换解决方法

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)
}

这可行,但它使用了很多转换,应该避免

其他语言(Haskell 和 Scala 是 best-known 语言)有一个解决方案,最终可能会添加到 Kotlin 中:类型 类。有关将它们添加到 Kotlin 的 (non-final) 提案,请参阅 https://github.com/Kotlin/KEEP/pull/87

在添加它们之前,您可以手动执行类似的操作:

interface 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.[=14=来判断]