Создание универсального массива в Котлине
Почему это не компилируется? Я получаю ошибку компиляции в 3 строке
Невозможно использовать T в качестве параметра типа reified. Используйте класс вместо
class Matrix2d<T>(val rows: Int, val cols: Int, init: (Int, Int) -> T) {
var data = Array(rows * cols, { i ->
val r = Math.floor(i.toDouble() / cols).toInt()
init(r, i - r * cols)
})
operator fun get(row: Int, col: Int): T = data[row * cols + col]
operator fun set(row: Int, col: Int, v: T) = {
data[row * cols + col] = v
}
}
Решение
Я добавил фабричную функцию, которая выглядит как второй конструктор, но реализована во встроенной функции
class Matrix2d<T>(val rows: Int, val cols: Int, private val data: Array<T>) {
companion object {
operator inline fun <reified T> invoke(rows: Int, cols: Int, init: (Int, Int) -> T): Matrix2d<T> {
return Matrix2d(rows, cols, Array(rows * cols, { i ->
val r = Math.floor(i.toDouble() / cols).toInt()
init(r, i - r * cols)
}))
}
}
init {
if (rows * cols != data.size) throw IllegalArgumentException("Illegal array size: ${data.size}")
}
operator fun get(row: Int, col: Int): T = data[row * cols + col]
operator fun set(row: Int, col: Int, v: T) {
data[row * cols + col] = v
}
}
2 ответа
Массивы JVM, на которые отображаются массивы Kotlin, требуют, чтобы тип элемента был известен во время компиляции, чтобы создать экземпляр массива.
Таким образом, вы можете создать экземпляр Array<String>
или же Array<Any>
, но нет Array<T>
где T
это параметр типа, представляющий тип, который стирается во время компиляции и, следовательно, неизвестен. Чтобы указать, что параметр типа должен быть известен во время компиляции, он помечается reified
модификатор.
Есть несколько вариантов, что вы можете сделать в этой ситуации:
использование
MutableList<T>
для хранения элементов, для которых не требуется reified T:// MutableList function, available in Kotlin 1.1 val data = MutableList(rows * cols, { i -> val r = i / cols init(r, i % cols) }) // or in Kotlin 1.0 val data = mutableListOf<T>().apply { repeat(rows * cols) { i -> val r = i / cols add(init(r, i % cols)) } }
Создайте массив из встроенной функции с параметром reified типа:
inline fun <reified T> Matrix2d(val rows: Int, val cols: Int, init: (Int, Int) -> T) = Matrix2d(rows, cols, Array(rows * cols, { .... }) class Matrix2d<T> @PublishedApi internal constructor( val rows: Int, val cols: Int, private val data: Array<T> )
использование
Array<Any?>
в качестве хранилища, и приведите его значения кT
вget
функция:val data = Array<Any?>(rows * cols, { .... }) operator fun get(row: Int, col: Int): T = data[row * cols + col] as T
Передать параметр типа
Class<T>
или жеKClass<T>
конструировать и использовать Java-отражение для создания экземпляра массива.
Лично, лучший обходной путь для меня был:
@Suppress("UNCHECKED_CAST")
var pool: Array<T?> = arrayOfNulls<Any?>(initialCapacity) as Array<T?>