在 Kotlin 中创建通用二维数组
Create generic 2D array in Kotlin
假设我有一个泛型 class,我需要一个泛型 T
的二维数组。如果我尝试以下
class Matrix<T>(width: Int, height: Int) {
val data: Array<Array<T>> = Array(width, arrayOfNulls<T>(height))
}
编译器会抛出一条错误消息“无法使用 'T' 作为具体化类型参数。请改用 class。”。
问题是用非具体化类型参数T调用arrayOfNulls<T>(height)
。但是我们也不能使T
具体化,编译器会抛出以下错误:“只能具体化内联函数的类型参数"
这就是我们要做的。我们使用内联工厂方法代替构造函数:
class Matrix<T> private(width: Int, height: Int, arrayFactory: (Int) -> Array<T>) {
class object {
inline fun <reified T>invoke(width: Int, height: Int)
= Matrix(width, height, { size -> arrayOfNulls<T>(size) })
}
val data: Array<Array<T>> = Array(width, { size -> arrayFactory(size) })
}
注意,构造函数现在是私有的,因此调用 Matrix()
将正确调用新的 invoke() 方法(related question). Because the method is inlined, we can use reified generics 这使得调用 arrayOfNulls<T>
.
只是因为语法有所改变,所以这是我的看法:
class Array2D<T> (val xSize: Int, val ySize: Int, val array: Array<Array<T>>) {
companion object {
inline operator fun <reified T> invoke() = Array2D(0, 0, Array(0, { emptyArray<T>() }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int) =
Array2D(xWidth, yWidth, Array(xWidth, { arrayOfNulls<T>(yWidth) }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int, operator: (Int, Int) -> (T)): Array2D<T> {
val array = Array(xWidth, {
val x = it
Array(yWidth, {operator(x, it)})})
return Array2D(xWidth, yWidth, array)
}
}
operator fun get(x: Int, y: Int): T {
return array[x][y]
}
operator fun set(x: Int, y: Int, t: T) {
array[x][y] = t
}
inline fun forEach(operation: (T) -> Unit) {
array.forEach { it.forEach { operation.invoke(it) } }
}
inline fun forEachIndexed(operation: (x: Int, y: Int, T) -> Unit) {
array.forEachIndexed { x, p -> p.forEachIndexed { y, t -> operation.invoke(x, y, t) } }
}
}
这还允许您以类似于一维数组的方式创建二维数组,例如像
val array2D = Array2D<String>(5, 5) { x, y -> "$x $y" }
和access/set 索引运算符的内容:
val xy = array2D[1, 2]
假设我有一个泛型 class,我需要一个泛型 T
的二维数组。如果我尝试以下
class Matrix<T>(width: Int, height: Int) {
val data: Array<Array<T>> = Array(width, arrayOfNulls<T>(height))
}
编译器会抛出一条错误消息“无法使用 'T' 作为具体化类型参数。请改用 class。”。
问题是用非具体化类型参数T调用arrayOfNulls<T>(height)
。但是我们也不能使T
具体化,编译器会抛出以下错误:“只能具体化内联函数的类型参数"
这就是我们要做的。我们使用内联工厂方法代替构造函数:
class Matrix<T> private(width: Int, height: Int, arrayFactory: (Int) -> Array<T>) {
class object {
inline fun <reified T>invoke(width: Int, height: Int)
= Matrix(width, height, { size -> arrayOfNulls<T>(size) })
}
val data: Array<Array<T>> = Array(width, { size -> arrayFactory(size) })
}
注意,构造函数现在是私有的,因此调用 Matrix()
将正确调用新的 invoke() 方法(related question). Because the method is inlined, we can use reified generics 这使得调用 arrayOfNulls<T>
.
只是因为语法有所改变,所以这是我的看法:
class Array2D<T> (val xSize: Int, val ySize: Int, val array: Array<Array<T>>) {
companion object {
inline operator fun <reified T> invoke() = Array2D(0, 0, Array(0, { emptyArray<T>() }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int) =
Array2D(xWidth, yWidth, Array(xWidth, { arrayOfNulls<T>(yWidth) }))
inline operator fun <reified T> invoke(xWidth: Int, yWidth: Int, operator: (Int, Int) -> (T)): Array2D<T> {
val array = Array(xWidth, {
val x = it
Array(yWidth, {operator(x, it)})})
return Array2D(xWidth, yWidth, array)
}
}
operator fun get(x: Int, y: Int): T {
return array[x][y]
}
operator fun set(x: Int, y: Int, t: T) {
array[x][y] = t
}
inline fun forEach(operation: (T) -> Unit) {
array.forEach { it.forEach { operation.invoke(it) } }
}
inline fun forEachIndexed(operation: (x: Int, y: Int, T) -> Unit) {
array.forEachIndexed { x, p -> p.forEachIndexed { y, t -> operation.invoke(x, y, t) } }
}
}
这还允许您以类似于一维数组的方式创建二维数组,例如像
val array2D = Array2D<String>(5, 5) { x, y -> "$x $y" }
和access/set 索引运算符的内容:
val xy = array2D[1, 2]