在Kotlin中创建通用的二维数组

14
假设我有一个泛型类,我需要一个通用类型 T 的二维数组。如果我尝试以下操作:
class Matrix<T>(width: Int, height: Int) {
    val data: Array<Array<T>> = Array(width, arrayOfNulls<T>(height))
}

编译器会抛出错误,提示“无法将'T'用作具体类型参数,请使用类代替。”
2个回答

11

仅仅因为语法有了一些变化,这是我的看法:

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

并使用索引运算符访问/设置内容:

val xy = array2D[1, 2]

这是一个不错的解决方案,但有点有问题。因为它通过公共构造函数设置数组属性并同时设置xSize和ySize,这可能会引起误解。 - greg

9
问题在于使用不具备实体化类型参数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()方法(相关问题)。由于该方法被内联,我们可以使用具体化泛型,从而可以调用arrayOfNulls<T>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接