Kotlin 中使用数组的安全调用令人困惑

Safe Calls in Kotlin with Array is confuse

有一个数组: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. 可以看到Alternative 1&2里面有Inspection Note The condition 'it != null' is always true检查对不对?因为我只想保证里面的非空项notes 可以放在 payloadJson.
  2. 备选方案3中,可以看到filterNotNull()?.里面有Safe Call,这里是否需要?,因为我复习了源代码,filterNotNull()的结果不能为null,但是当我在那里删除?时,编译失败。

检查是对的。您将 notes 变量声明为不可空项的可空数组。

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

考虑到这一点,filterNotNull()?. 对于此数组是必需的,因为它可以为空。您可以在 Kotlin documentation.

中找到有关 Kotlin 空安全的更多信息

notes的类型是Array<KeyValueNote>?,也就是说数组的元素不能为null,但是数组本身可以。因此,您在 "I want" 部分中的代码是正确的。一个较短的替代方案是:

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

关于您的备选方案:

  • 备选方案 1:永远不要这样使用 let。它应该是一个安全的调用 ?.(就像在备选方案 2 中一样),没有别的。在那种情况下,当我看到 let 时,我的心在流血:(

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

  • 备选方案 3:由于数组的元素不能为空(因为它们的类型),filterNotNull 等同于 toList,因为它只是复制内容

我猜您对在不同范围内使用的 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 的编译器说明也是如此,原因相同:val items:Array<KeyValueNote>? 不能保存 null 值 - 但 items 本身可以是 null.

第三个替代方案安全调用了 filterNotNull,其中 returns 源集合删除了 null 值。但是,如前所述,Array<KeyValueNote> 中不能有 null 值,因此不需要 filterNotNull

总之表达式可以写成:

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