用数组安全地调用Kotlin是令人困惑的

有一个数组: notes: Array<KeyValueNote>? 我在下面的代码中使用Kotlin 1.0.5-2

我想要

 if (notes != null) { for (note in notes) { // Put the note to the payload Json object only if the note is non-null. payloadJson.put(note.key, note.value) } } 

但有几个变化

  // Alternative 1. notes?.let { it.takeWhile { it != null /** Inspection will note The condition 'it != null' is always true' in here**/ }.forEach { payloadJson.put(it.key, it.value) } } // Alternative 2. notes?.takeWhile { it != null /** Inspection will note The condition 'it != null' is always true' in here**/ }?.forEach { payloadJson.put(it.key, it.value) } // Alternative 3. notes?.filterNotNull()?.forEach { payloadJson.put(it.key, it.value) } 

我的问题

  1. 你可以看到有检查注意在替代方案1和2中, The condition 'it != null' is always true检查是否正确? 因为我想确保只有notes的非空项可以被放到payloadJson
  2. 在备选方案3中,您可以看到filterNotNull()?.有一个安全调用filterNotNull()?.是否? 在这里需要吗? ,因为我查看源代码, filterNotNull()的结果不能为null,但是当我删除? 在那里,编译失败了。

notes的类型是Array<KeyValueNote>? ,这意味着数组的元素不能为null ,而是数组本身就可以。 因此,您在“我想要”部分中的代码是正确的。 较短的替代方案是:

 notes?.forEach { payloadJson.put(it.key, it.value) } 

关于您的选择:

  • 选择1:永远不要这样let 。 这应该是一个安全的电话?. (如方案2),没有别的。 当我看到在这种情况下,我的心脏流血:(

  • 选择2: takeWhilefilter显然不是一回事。 我想你想filterNotNull ,就像在替代方案3

  • 方案3:由于数组的元素不能为null(因为它们的类型), filterNotNull相当于toList因为它只是复制内容

检查是正确的。 你声明你的笔记变量是不可为空的项目的可空数组。

 notes: Array<KeyValueNote>? // Can be null, cannot contain nulls. notes: Array<KeyValueNote?> // Cannot be null, can contain nulls. 

考虑到这一点, filterNotNull()?. 这个数组是必须的,因为它是可空的。 您可以在Kotlin文档中找到有关Kotlin null安全性的更多信息。

我想你是在不同的范围使用it参数混淆。 第一个选择可以改写为:

 notes?.let { notesSafe:Array<KeyValueNote> -> // notesSafe is not null here notesSafe .takeWhile { item:KeyValueNote -> item != null } // item is already not null by it's type definition .forEach { payloadJson.put(it.key, it.value) } } 

第二个选择几乎是一样的,关于item:KeyValueNote的编译器注意item:KeyValueNote是同样的原因: val items:Array<KeyValueNote>? 不能保存null值 – 但是items本身可能为null

第三个替代方法可以安全地调用filterNotNull ,它将返回删除null值的源集合。 然而正如所提到的Array<KeyValueNote>不能filterNotNull值,因此filterNotNull不是必需的。

总之,这个表达可以写成:

 notes?.forEach { payloadJson.put(it.key, it.value) }