Создайте общий 2D-массив в Котлине

Предположим, что у меня есть общий класс, и мне нужен 2D-массив общего типа T Если я попробую следующее

 class Matrix<T>(width: Int, height: Int) { val data: Array<Array<T>> = Array(width, arrayOfNulls<T>(height)) } 

компилятор выдает сообщение об ошибке « Невозможно использовать« T »в качестве параметра типа reified. Вместо этого используйте класс. ».

    Просто потому, что синтаксис немного переместился, вот мой вопрос:

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

    Это также позволяет вам создавать 2d-массивы аналогично массиву 1d, например, что-то вроде

     val array2D = Array2D<String>(5, 5) { x, y -> "$x $y" } 

    и доступ / установить содержимое с помощью оператора индексирования:

     val xy = array2D[1, 2] 

    Проблема заключается в вызове arrayOfNulls<T>(height) с параметром типа non-reified T. Но мы также не можем сделать T reified, компилятор будет вызывать следующую ошибку: « Только параметры типа встроенных функций могут быть подтверждены »

    Так вот что мы собираемся делать. Вместо конструктора мы используем встроенный заводский метод:

     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> .