Kotlin:泛型方法和for循环询问iterator()

这是一个简单的泛型方法,并且传递for循环中的参数值会导致错误:

for-loop范围必须有和iterator()方法

fun main(args: Array<String>) { val arr: IntArray = intArrayOf(1,2,3,4) val charA: CharArray = charArrayOf('a','b','c','d') printMe(arr) printMe(charA) } fun <T>printMe(args: T){ for (items in args){ println(items) } } 

我如何使它迭代char[]array

Kotlin中的for循环按照惯例工作, 静态寻找一个名为iterator的操作符成员,它必须返回可以迭代的东西,即反过来操作员nexthasNext

这些成员的operator修饰符需要指定成员满足一些约定,即迭代约定。

由于args的类型是T并且每个可能的类型T中都没有iterator成员,所以不能轻易迭代。

但是,您可以为printMe提供一个额外的参数,它知道如何从T的实例中获取迭代器,然后使用它来获取迭代器并对其进行迭代:

 fun main(args: Array<String>) { val arr: IntArray = intArrayOf(1,2,3,4) val charA: CharArray = charArrayOf('a','b','c','d') printMe(arr, IntArray::iterator) printMe(charA, CharArray::iterator) } fun <T> printMe(args: T, iterator: T.() -> Iterator<*>) { for (item in args.iterator()) { println(item) } } 

这里T.() -> Iterator<*>是一个表示接收方函数的类型。 这个类型的实例可以在T上调用,就好像它们是扩展一样。

这个片段的工作原理是因为迭代器本身有一个运算符扩展函数Iterator<T>.iterator() = this只是返回该迭代器,因此允许通过for循环遍历迭代器。

这实际上有点微妙。

关键问题是变量arr的类型是IntArrayIntArray不是从Array派生的。 同样,虽然IntArray有一个iterator()函数,但它并不实现Iterable<>

对于CharArray变量也是如此。

事实上, IntArrayIntArray以及Array<T>似乎没有Any以外的任何公共基类或接口。 所以你要么坚持传递一个对象,在printMe中进行类型printMe ,要么使用重载。

类型检查版本看起来像

 printMe(args:Any) { if(args is IntArray) { for(item in args) { println(item) } } else if (args is CharArray) { for(item in args) { println(item) } } else { println("Not an IntArray or a CharArray") } } 

重载看起来像这样

 printMe(args:IntArray) { for(item in args) { println(item) } } printMe(args:CharArray) { for(item in args) { println(item) } } 

国际海事组织重载是更好的选择,因为你不能最终传递一个对象,你不能错误地处理。

问题是编译器不知道你正在传递一个ArrayT可以是任何类型的。

解决这个问题的一个方法是使用is运算符:

 fun <T>printMe(args: T){ if(args is Array<*>) { for (items in args) { println(items) } } }