【问题标题】:Kotlin NDArray with a lambda constructor with generic return typeKotlin NDArray 带有具有通用返回类型的 lambda 构造函数
【发布时间】:2016-02-23 15:42:48
【问题描述】:

我正在尝试在 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'作为具体类型参数。改用类”。为什么?

编辑:

如果我用我自己的 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 与常规 Array 区别对待,因为两者都具有相同的构造函数?

【问题讨论】:

  • 为什么不简单地class NDArray&lt;T&gt;(i:Int, j:Int, f: (Int) -&gt; T) { val values: Array&lt;Int&gt; = Array&lt;Int&gt;(i*j,f) }
  • 绝对更简洁,但问题仍然存在,因为 Array 应该是 T 类型,而不是 Int。
  • 非惯用的 Kotlin 代码难以阅读。请查看编辑
  • 简洁明了。编辑接受,谢谢!
  • 要让MyArrayArray 一样工作,它必须有一个reifiled T 通用参数。目前只允许 inline 函数使用

标签: arrays generics kotlin type-erasure


【解决方案1】:

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

如果您想围绕标准 Array&lt;T&gt; 创建一个自定义包装器,它必须如下所示:

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

reified 关键字意味着您的T 不会被删除,并且可以用于需要真正类的地方,例如调用Array() 构造函数。

请注意,类构造函数不支持此语法,但对于工厂函数仍然有用(必须为inlined)

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

【讨论】:

  • 认为它与类型擦除有关。如果您从 JVM 的角度来看,我可以看到在运行时创建泛型类型 T[] 的数组的问题。从 Kotlin 的角度来看,我仍然有点困惑,请参阅编辑。
  • 如果不使用工厂模式,基本上不可能包装 Array() 吗?顺便说一句,请参阅编辑
【解决方案2】:

根据 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 用作构造函数。构造调用约定可以使用操作符调用来完成。现在可以了:

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

fun zero(i:Int) =  0.0 

唯一的问题(除了复杂的语法 invoke() )是 NDArray 构造函数需要是公共的。有没有更好的办法?

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

【讨论】:

    猜你喜欢
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多