与Java中一样,任何为Iterable
的对象都可以在增强的for循环中使用。我原以为Kotlin也是如此,直到我发现kotlin.collections.Map
根本不是Iterable
。
来自标准库源代码:
public interface Map<K, out V> {
// ....
如果不是,那么这样的事情怎么可能发生?:
val map: Map<String, Int> = HashMap()
// ...
for ((s, i) in map) {
println(s)
println(i)
// works perfectly
}
最后,是否有可能制作支持这种语法的自定义类?如果有,怎么做?
Kotlin for循环是由约定:
定义的定义的,这意味着它们的语义是通过从一种语法形式扩展到另一种语法形式来定义的。Kotlin中的一些语法形式是由约定
对于for(VarDecl in C) Body
,展开后的语法形式为:
when(val $iterator = C.iterator()) {
else -> while ($iterator.hasNext()) {
val VarDecl = $iterator.next()
<... all the statements from Body>
}
不需要特定的接口,只需要重载解析为iterator()
、hasNext()
和next()
找到适当的operator
重载。作为一个极端的例子,这将编译!
fun main() {
for (s in Foo()) { // no error here!
}
}
class Foo {
operator fun iterator(): Bar = Bar()
}
class Bar {
operator fun hasNext() = false
operator fun next() = ""
}
在您的示例中,存在Map
的扩展函数iterator
:
operator fun <K, V> Map<out K, V>.iterator(): Iterator<Entry<K, V>>
andMutableMap
:
@JvmName("mutableIterator")
operator fun <K, V> MutableMap<K, V>.iterator(): MutableIterator<MutableEntry<K, V>>
iterator
方法不必在Map
中声明——只要重载解析可以解析它,for循环就可以工作。这同样适用于next
和hasNext
。
operator fun iterator(): Iterator<Something>
但我仍然建议你实现Iterable
,因为这样你就可以免费获得所有的Iterable
扩展函数:)