首页 文章

带有泛型返回类型的lambda构造函数的Kotlin NDArray

提问于
浏览
4

我正在尝试在Kotlin中创建一个非常简单的通用NDArray类,它将lambda表达式作为init函数 .

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) {
    val values: Array<T> =  Array(i * j, f)
}

典型用法是:

fun main(args: Array<String>){
    val m = NDArray(4, 4, ::zero)
}

fun zero(i: Int) =  0.0

我的问题是Kotlin编译器抱怨构造函数中的值的初始化

values = Array(i * j, f)

通过说“不能使用'T'作为具体的类型参数 . 使用类代替” . 为什么?

EDIT:

如果我用我自己的MyArray替换Kotlin Array实现,它会编译:

class NDArray<T>(i: Int, j: Int, f: (Int) -> T) {
    val values: MyArray<T> =  MyArray(i * j, f)
}

class MyArray<T>(i:Int, init: (Int) -> T) {
    ...
}

不知道为什么当两个具有相同的构造函数时,Kotlin将MyArray与常规数据区别对待?

2 回答

  • 4

    创建Java数组需要指定元素类型 . 对于类,元素类型仅作为类的类型参数提供,Java中的泛型在运行时被擦除 . 因此,数组的元素类型是未知的,并且无法创建它 .

    如果您想在标准 Array<T> 周围创建自定义包装器,则必须如下所示:

    class NDArray<reified T>(i:Int, j:Int, init: (Int) -> T) {
        val arr = Array<T>(i * j, init)
    }
    

    reified 关键字表示您的 T 未被删除,并且可能在需要真正类的地方使用,例如调用 Array() 构造函数 .

    请注意,这个 syntax is not supported 用于类构造函数,但它仍然适用于工厂函数(必须是 inline d)

    fun <reified T> arrayFactory(i:Int, j:Int, init: (Int) -> T) = Array<T>(i * j, init)
    
  • 0

    根据yole和voddan的输入,这是我到目前为止找到的最佳解决方案:

    class NDArray<T>(val values: Array<T> ){
    
        companion object Factory{
            inline operator fun <reified T>invoke(i: Int, j: Int, noinline init: (Int) -> T) = NDArray(Array(i * j,init))
        }
    }
    

    这允许通过使用伴随对象将reified用作构造函数 . 可以使用operator invoke完成构造调用约定 . 这现在有效:

    fun main(args: Array<String>){
        val m = NDArray(4,4, ::zero)
    }
    
    fun zero(i:Int) =  0.0
    

    唯一的问题(复杂的语法invoke()除外)是NDArray构造函数需要是公共的 . 还有更好的方法吗?

    注意!以下问题KT-11182会影响此设计模式

相关问题