在Kotlin中实例化通用数组

Lan*_*ter 13 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
   }
}
Run Code Online (Sandbox Code Playgroud)

我添加了一个工厂函数,它看起来像第二个构造函数,但是在内联函数中实现

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
   }
}
Run Code Online (Sandbox Code Playgroud)

Ily*_*lya 13

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

所以,你可以实例Array<String>Array<Any>,而不是Array<T>在那里T是一个类型参数,表示在编译时被擦除,因此是未知类型.要指定在编译时必须知道类型参数,它将使用reified修饰符进行标记.

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

  1. 使用MutableList<T>存储元件,不需要物化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))
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用带有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>
        ) 
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用Array<Any?>作为存储,并投它的值Tget功能:

    val data = Array<Any?>(rows * cols, { .... })
    
    operator fun get(row: Int, col: Int): T = data[row * cols + col] as T
    
    Run Code Online (Sandbox Code Playgroud)
  4. 传递类型的参数Class<T>KClass<T>构造函数,并使用java反射创建数组的实例.