具有可为空和不可为空的通用数组的方法调用

时间:2018-11-20 15:00:57

标签: generics kotlin

我想在Kotlin中编写一个函数,该函数采用String数组,并对数组中所有项目的长度求和。我想到了这样的事情:

fun sumItems(values: Array<String?>): Int {
    var sum: Int = 0
    values.forEach { if(it != null) sum += it.length }
    return sum
}

这很好用,但是很遗憾,我无法为Array<String>调用此方法,因为那时我收到类型不匹配错误。我也无法创建函数sumItems(values: Array<String>): Int,因为它具有相同的JVM签名。我可以将论点投向Array<String?>,但这是不安全的。

那么Kotlin有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

尝试一下:

fun sumItems(values: Array<out String?>) = values.sumBy { it?.length ?: 0 }

您可能希望使其成为扩展方法:

fun Array<out String?>.sumItems() = sumBy { it?.length ?: 0 }

由于通用类型上的Array<String>修饰符,因此这对Array<String?>out都适用。这说明values参数(或扩展方法的接收方)必须是一个产生可空字符串的数组。显然Array<String?>会生成可为空的字符串,因此可以有效地传递。但是Array<String> 会生成可为空的字符串,因为字符串始终可以转换为可为空的字符串。 here对此进行了详细说明。

答案 1 :(得分:2)

即使Yoni Gibbs的回答是正确的,我还是希望在这里走另一条路,即使用非空类型,例如:

fun sumItems(values: Array<String>) = values.sumBy { it.length }

注释中还提到了m0skit0:如果列表中确实有null个值,请在求和之前将其过滤掉,例如:

val arrayWithNulls = arrayOf("hello", null, "world")
arrayWithNulls.filterNotNull()
              .let(::sumItems)

或更妙的是:只需跳过该方法即可:

arrayWithNulls.filterNotNull()
              .sumBy { it.length } // or .sumBy(String::length)

如果应用现有功能已经足够,为什么要引入新功能呢?

尝试尽早从数组中消除空值。否则,您的代码将变得更加复杂(添加大量null安全的东西),这会使代码的可读性降低。这样,您也可以跳过该filterNotNull