如何解决你如何用一个类创建一个数组?
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 举报,一经查实,本站将立刻删除。