微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

你如何用一个类创建一个数组?

如何解决你如何用一个类创建一个数组?

假设我有一个

open class Grid<R> {

    private val columns = mutablelistof<Column<R,*>>()

    private val _rows = mutablelistof<Row<R>>()

    val rows: List<Row<R>> get() = _rows.toList()

    ...

    private fun addRow(row: R) {
        val r = Row(row).also {
            columns.forEach { column -> it.addValue(column) }
        }
        _rows.add(r)
    }

    fun addRows(vararg rows: R) {
        rows.forEach { addRow(it) }
        dataHasChanged()
    }

    ...
}

其中 Row 是与本讨论无关的 R 的一些包装。

现在假设我想添加一个

fun replaceRows(newRows: List<R>) {
    _rows.clear()
    addRows(*newRows.toTypedArray())
}

这失败了,因为我

不能使用“R”作为具体化的类型参数。 改用类。

好吧,让我们试一试...

首先,让我们跟踪 R 类...

open class Grid<R> protected constructor(private val rowType: Class<R>) {
    companion object {
        inline operator fun <reified R> invoke(): Grid<R> {
            return Grid(R::class.java)
        }
    }

    private val columns = mutablelistof<Column<R,*>>()

    private val _rows = mutablelistof<Row<R>>()

    val rows: List<Row<R>> get() = _rows.toList()

    ...

    private fun addRow(row: R) {
        val r = Row(row).also {
            columns.forEach { column -> it.addValue(column) }
        }
        _rows.add(r)
    }

    fun addRows(vararg rows: R) {
        rows.forEach { addRow(it) }
        dataHasChanged()
    }

    fun replaceRows(newRows: List<R>) {
        _rows.clear()
        addRows(*newRows.toTypedArray()) //fails
    }

    ...
}

现在呢?如何将 newRows 列表传递给 addRows 函数

是的,我很清楚我可以通过创建一个接受列表的重载来解决这个问题:

    fun addRows(rows : List<R> ){
        rows.forEach { addRow(it) }
        dataHasChanged()
    }

    fun addRows(vararg rows: R) {
        addRows(rows.toList())
    }

    fun replaceRows(newRows: List<R>) {
        _rows.clear()
        addRows(newRows)
    }

这也让我摆脱了 rowType 和内联运算符的恶作剧,

我似乎无法找到关于如何实际执行错误消息建议的好答案,这让我很困扰。

因为老实说,就像

addRows(*newRows.stream().toArray() as Array<R>)

实在是太丑了。

(为什么展开运算符不能直接在列表上工作?会让事情变得更容易...)

解决方法

这是由于类型擦除以及数组已具体化类型的事实而造成的限制。您的解决方法 addRows(*newRows.stream().toArray() as Array<R>) 将抛出 ClassCastException,因为 Array 类型是具体化的,因此您不能将 Arrays 转换为具有不同类型的 Arrays。 stream.toArray() 创建一个 Array<Any>,无论流的泛型类型如何,因为流的类型在运行时被擦除。

toTypedArray 是一个内联函数,因此可以安全使用,因为它返回与输入列表类型匹配的实际数组类型。但是安全性要求编译器必须具体知道数组的类型。

由于具体化仅在局部函数级别起作用,因此它不会帮助您调用 toTypedArray

我能想到的唯一方法是使用 Java 反射来创建正确类型的数组,因此您可以使用 KClass 参数而不是 reified 函数来创建类型化数组:

@Suppress("UNCHECKED_CAST")
fun <T: Any> Collection<T>.toTypedArray(type: KClass<T>): Array<T> {
    @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
    val thisCollection = this as java.util.Collection<T>
    return thisCollection.toArray(java.lang.reflect.Array.newInstance(type.java,0) as Array<T>) as Array<T>
}

然后您可以在具有行类型属性的 Grid 类中使用此非内联版本的 toTypedArray()

    fun replaceRows(newRows: List<R>) {
        _rows.clear()
        addRows(*newRows.toTypedArray(rowType))
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。