Kotlin:泛型方法和for循环请求iterator()

时间:2017-05-30 00:05:24

标签: java generics kotlin

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

  

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

的值

3 个答案:

答案 0 :(得分:5)

Kotlin中的

for循环按惯例工作,为名为iterator的运算符成员静态查找 ,该成员必须返回可以迭代的内容,即依次为运算符成员{{ 1}}和next

这些成员上的

hasNext修饰符需要指定该成员是否满足某些约定,即迭代约定。

由于operator的类型为args且每种可能的类型T都没有iterator成员,因此无法轻松迭代。

但是你可以为T提供一个额外的参数,它知道如何从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) } } 是表示function with receiver的类型。可以在T.() -> Iterator<*>上调用该类型的实例,就好像它们是它的扩展名一样。

这个片段有效,因为返回的迭代器本身就有一个操作符扩展函数T,它只返回迭代器,因此允许用for循环遍历迭代器。

答案 1 :(得分:2)

这实际上有点微妙。

关键问题是变量arr的类型为IntArrayIntArray不是来自Array。同样,虽然IntArray具有iterator()功能,但它并未实现Iterable<>

CharArray变量也是如此。

事实上,IntArrayCharArray以及Array<T>似乎没有Any以外的任何公共基类或接口。所以你要么在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)
  }
}

IMO重载是更好的选择,因为你不能最终传递一个你不能错误处理的对象。

答案 2 :(得分:0)

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

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

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