在Kotlin中实例化通用数组

时间:2017-01-30 16:44:17

标签: generics kotlin

为什么这不编译?我在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 个答案:

答案 0 :(得分:8)

Kotlin数组映射到的JVM数组需要在编译时知道元素类型以创建数组实例。

因此,您可以实例化Array<String>Array<Any>,但不能Array<T> T,其中reified是一个类型参数,表示在编译时被删除的类型,因此未知。 要指定在编译时必须知道类型参数,它将标记为MutableList<T>修饰符。

有几种选择,在这种情况下你可以做什么:

  1. 使用// 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)) } } 存储元素,不需要知道T:

    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>
        ) 
    
  2. 使用带有reified类型参数的内联函数创建数组:

    Array<Any?>
  3. 使用T作为存储空间,并将其值转换为get函数中的val data = Array<Any?>(rows * cols, { .... }) operator fun get(row: Int, col: Int): T = data[row * cols + col] as T

    Class<T>
  4. 将类型KClass<T>response.text().then(function (text) { // do something with the text response }); 的参数传递给构造函数,并使用java反射创建数组实例。

答案 1 :(得分:-1)

就个人而言,对我来说最好的解决方法是:

@Suppress("UNCHECKED_CAST")
var pool: Array<T?> = arrayOfNulls<Any?>(initialCapacity) as Array<T?>