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" 通过传递参数进行操作。
像,sum
对List<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=来判断]
我想为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" 通过传递参数进行操作。
像,sum
对List<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=来判断]