为什么填充阵列工作正常
填充阵列从拉姆达作为第二通话过程中推断阵列的类型参数:
val strings = Array(10000, {"string"})
产生Array<String>
val strings = Array(10000, { it -> if (it % 2 == 0) "string" else null })
产生Array<String?>
因此改变声明的=
的不拉姆达没有做任何事情来帮助匹配左边。如果发生冲突,则会出现错误。
如何使arrayOfNulls工作
对于arrayOfNulls
问题,他们键入您指定的号召arrayOfNulls<String>
在函数签名被用作泛型类型T
和功能arrayOfNulls
返回Array<T?>
这意味着空。代码中没有任何内容会更改该类型。 fill
方法仅将值设置到现有数组中。
对此可空元素的数组转换为不可为空的元素的列表,使用方法:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
这是很好的,因为你的map
调用转换成一个列表,无论如何,那么为什么不事先转换。现在取决于数组的大小,这可能是高性能的,如果在CPU高速缓存中,副本可能会很快。如果是大的,没有高性能,可以让这个懒:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asSequence().filterNotNull()
val upper = strings.map { it.toUpperCase() } // no !! needed
或者,你可以通过做副本留在阵,但实际上这是没有意义的,因为你与map
撤消:
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings: Array<String> = Array(nullableStrings.size, { idx -> nullableStrings[idx]!! })
在Java或Kotlin代码(JetBrains研究了统计数据)中,数组确实不是很常见,除非代码正在进行真正的低级优化。使用列表可能会更好。
鉴于无论如何你可能会以列表结束,也许从那里开始并放弃阵列。
val nullableStrings = listOf("a","b",null,"c",null,"d")
val strings = nullableStrings.filterNotNull()
但是,如果你不能停止追求使用数组,而真的要投一个没有副本...
你总是可以写做两件事情的函数:一是,检查所有值是否为空,如果是,则返回抛出的数组不为null。这有点冒险,但只是因为差异是可以为空才是安全的。
首先,创建于Array<T?>
的扩展功能:
fun <T: Any> Array<T?>.asNotNull(): Array<T> {
if (this.any { it == null }) {
throw IllegalStateException("Cannot cast an array that contains null")
}
@Suppress("CAST_NEVER_SUCCEEDS")
return this as Array<T>
}
然后使用此功能的新功能进行转换(元素选中为NOT NULL施法):
val nullableStrings = arrayOfNulls<String>(10000).apply { fill("hello") }
val strings = nullableStrings.asNotNull() // magic!
val upperStrings = strings.map { it.toUpperCase() } // no error
但我觉得脏甚至在谈论最后的选择。
我添加了一个更直接解决问题的答案。解释为什么会发生这种情况,以及考虑到上下文(您最终列出了列表,以便为什么不早些拥抱它们)的解决方案,以及如果您无法抗拒的黑客版本来投射阵列。 –