Generics 具有可为null和不可为null的泛型数组的方法调用
我想在Kotlin中编写一个函数,它接受一个字符串数组,并对数组中所有项的长度求和。我想到了这样的事情:Generics 具有可为null和不可为null的泛型数组的方法调用,generics,kotlin,Generics,Kotlin,我想在Kotlin中编写一个函数,它接受一个字符串数组,并对数组中所有项的长度求和。我想到了这样的事情: fun sumItems(values: Array<String?>): Int { var sum: Int = 0 values.forEach { if(it != null) sum += it.length } return sum } fun-sumtimes(值:数组):Int{ 变量和:Int=0 values.forEach{if(i
fun sumItems(values: Array<String?>): Int {
var sum: Int = 0
values.forEach { if(it != null) sum += it.length }
return sum
}
fun-sumtimes(值:数组):Int{
变量和:Int=0
values.forEach{if(it!=null)sum+=it.length}
回报金额
}
这非常有效,但不幸的是,我不能为Array
调用此方法,因为我得到了一个类型不匹配错误。我也无法创建函数sumtimes(值:Array):Int
,因为它具有相同的JVM签名。我可以将参数强制转换为数组
,但这是不安全的
那么在Kotlin有没有更好的方法可以做到这一点呢?试试这个:
fun sumItems(values: Array<out String?>) = values.sumBy { it?.length ?: 0 }
fun-sumtimes(值:数组)=values.sumBy{it?.length?:0}
您可能希望将其改为扩展方法:
fun Array<out String?>.sumItems() = sumBy { it?.length ?: 0 }
fun Array.sumtimes()=sumBy{it?.length?:0}
这将适用于Array
和Array
,因为泛型类型上有out
修饰符。这表明值参数(或扩展方法的接收者)必须是生成可为空字符串的数组。显然,Array
会生成可为空的字符串,因此可以有效地传入。但是Array
也会生成可为空的字符串,因为字符串总是可以转换为可为空的字符串。这将得到更详细的解释。尝试以下方法:
fun sumItems(values: Array<out String?>) = values.sumBy { it?.length ?: 0 }
fun-sumtimes(值:数组)=values.sumBy{it?.length?:0}
您可能希望将其改为扩展方法:
fun Array<out String?>.sumItems() = sumBy { it?.length ?: 0 }
fun Array.sumtimes()=sumBy{it?.length?:0}
这将适用于Array
和Array
,因为泛型类型上有out
修饰符。这表明值参数(或扩展方法的接收者)必须是生成可为空字符串的数组。显然,Array
会生成可为空的字符串,因此可以有效地传入。但是Array
也会生成可为空的字符串,因为字符串总是可以转换为可为空的字符串。这将得到更详细的解释。即使Yoni Gibbs的答案是正确的,我还是选择另一种方法,即使用不可为空的类型,例如:
fun sumItems(values: Array<String>) = values.sumBy { it.length }
或者更好:跳过该方法并执行以下操作:
arrayWithNulls.filterNotNull()
.sumBy { it.length } // or .sumBy(String::length)
如果应用现有功能已经足够,为什么要引入新功能
尝试尽早从数组中消除空值。否则,您的代码会变得更复杂(添加了许多空安全的东西),这会降低代码的可读性。这样,您也可以跳过filterNotNull
即使Yoni Gibbs的答案是正确的,我还是选择另一种方法,即使用不可为null的类型,例如:
fun sumItems(values: Array<String>) = values.sumBy { it.length }
或者更好:跳过该方法并执行以下操作:
arrayWithNulls.filterNotNull()
.sumBy { it.length } // or .sumBy(String::length)
如果应用现有功能已经足够,为什么要引入新功能
尝试尽早从数组中消除空值。否则,您的代码会变得更复杂(添加了许多空安全的东西),这会降低代码的可读性。这样,您也可以跳过filterNotNull
我想这不是被问到的问题:“我不能为数组调用此方法,因为我得到了一个类型不匹配错误”。您可以为Array
和Array
调用它。我会用更多的细节更新我的答案。哦,你是对的,我不太习惯使用out/in修饰词,非常好的答案!作为解决问题的正确答案,我只能建议尽快消除null
值,这样代码中就不会充满大量空安全调用;-)为什么这不适用于列表
?如果我有fun-foo(c:MutableCollection)
我可以调用foo(mutableListOf())
但不能调用foo(mutableListOf())
。还有什么要注意的吗?我想这不是被问到的问题:“我不能为数组调用此方法,因为我得到了一个类型不匹配错误”。你可以为Array
和Array
调用它。我会用更多的细节更新我的答案。哦,你是对的,我不太习惯使用out/in修饰词,非常好的答案!作为解决问题的正确答案,我只能建议尽快消除null
值,这样代码中就不会充满大量空安全调用;-)为什么这不适用于列表
?如果我有fun-foo(c:MutableCollection)
我可以调用foo(mutableListOf())
但不能调用foo(mutableListOf())
。还有什么要注意的吗?你真的需要这个函数吗?有趣的sumtimes(值:数组):Int是否已经足够了?如果不是,则只使用数组
作为参数类型。Yoni Gibbs的回答已经说明了这一点,也说明了该方法如何更加简化……我将其声明为sumtimes(values:Array)
,当我需要传递数组时,我将使用filterNotNull
对其进行过滤。我将采用与@m0skit0相同的路径。这使代码更加清晰明了;-)但是filterNotNull返回一个列表:(调用filterNotNull
的问题是,您正在内存中创建第二个集合。并且您必须执行两次循环。在大多数情况下,这可能可以忽略不计,但如果使用大量数据,这不是最有效的方法。您真的需要这样的函数吗?不是很有趣的sumtimes(值:Array):Int
已经足够了吗?如果没有,那么就使用Array
作为参数类型。Yoni Gibbs的回答已经说明了这一点,以及该方法可以如何更加简化……我将其声明为sumtimes(值:Array)
当我需要传递一个数组时,我会用filterNotNull
对它进行过滤