Ely*_*lye 5 collections kotlin
在 Kotlin 集合(列表、数组和映射)中,为了获取大小,我们已经有了size. 有什么用count()?
val list = listOf(1, 2, 3)
list.size
list.count()
val map = mapOf(1 to 1, 2 to 2, 3 to 3)
map.size
map.count()
val array = arrayOf(1, 2, 3)
array.size
array.count()
Run Code Online (Sandbox Code Playgroud)
本质上,如果我们在后台检查它们,它们就会返回size。
size并且count()来自不同的接口。size定义在 上kotlin.collections.Collection,List和Set都实现:
public interface Collection<out E> : Iterable<E> {
// Query Operations
/**
* Returns the size of the collection.
*/
public val size: Int
...
Run Code Online (Sandbox Code Playgroud)
while是定义在(继承自)count()的扩展方法:kotlin.collections.IterableCollection
/**
* Returns the number of elements in this collection.
*/
public fun <T> Iterable<T>.count(): Int {
if (this is Collection) return size
var count = 0
for (element in this) checkCountOverflow(++count)
return count
}
Run Code Online (Sandbox Code Playgroud)
因此,仅仅继承自Iterables Collection,包括Lists 和Sets,count()就会自动给出一个方法。我们肯定希望Collection继承 from ,Iterable以便我们可以将 aCollection传递给接受任何Iterable. 然后,最后,Map(不是 a Collection)也获得size属性和方法,以便与和count()保持一致。ListSet
从技术上讲,我想这已经回答了为什么集合具有该方法的问题count(),但它还不是一个令人满意的解释,因为它引发了一个后续问题:那么为什么Collections 具有该size属性?为什么标准库开发人员不干脆添加size,而是让我们调用count()s Collection?
count()上面引用的的实现向我们展示了该问题的答案:size是性能优化。Collection Iterable当对非n个元素调用时,时间复杂度count()为O(n),因为它循环遍历可迭代中的所有元素。当调用 a 时Collection,它应该具有O(1)时间复杂度,因为它只是遵循size属性(希望评估的时间复杂度为O(1) !)。
接下来我们可能会问:这种优化可以通过其他方式实现吗?标准库开发人员不能简单地让他们实现的所有成员函数以O(1) 的Collection时间复杂度提供自己的count()成员函数,而不是使用附加属性使 API 变得复杂吗?
没有。因为扩展是静态解析的- 所以如果您没有size, 而是在 、 、 等上提供了O ( 1)实现,那么当您传递or 或时,这些O(1)实现将不会被使用一个以任意值作为参数并调用其方法的函数;相反,调用将静态解析为O(n)扩展方法。count()ListMapSetListMapSetIterablecount()
因此,让size和count()两者都存在是能够count()在所有s 上可用并且对于s 来说Iterable也是O(1) 的Collection唯一方法。
最后一点,如果您想知道为什么count()是方法并且size是属性,编码约定提供了线索:
函数与属性 在某些情况下,不带参数的函数可以与只读属性互换。尽管语义相似,但在何时更喜欢其中一种方面存在一些风格约定。
当底层算法满足以下条件时,优先选择属性而不是函数:
不抛出
计算成本低(或在第一次运行时缓存)
如果对象状态未更改,则在调用中返回相同的结果
(加粗我的)。由于count()计算(可能)昂贵但size便宜,因此应该将其count()设为方法和size属性 - 这确实是标准库开发人员所做的。