Kotlin: generic method and loop for iterator request ()
This is a simple generic method, and when passing in values, the args in for loop raises an error:
the for-loop range must also have an iterator () method
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)
}
}
how can i make it repeat the values ββfor char[]
botharray
source to share
The for-loop in Kotlin works by convention, statically stating a named member statement iterator
that should return something that can be iterated over, i.e. something that has in turn member members next
and hasNext
.
operator
for such members, it must indicate that the member must satisfy some convention, namely an iterative convention.
Since it args
has a type T
and does not exist iterator
in all possible types T
, it cannot be easily overwritten.
However, you can provide an additional parameter printMe
that knows how to get an iterator from an instance T
, and then use it to get an iterator and iterate over it:
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)
}
}
Here T.() -> Iterator<*>
is a type that denotes a function with a sink . Instances of this type can be called on T
as if they were extensions of it.
This snippet works because the returned iterator itself has a statement extension function Iterator<T>.iterator() = this
that simply returns that iterator, allowing the iterator to loop through with a while loop.
source to share
It's a bit subtle actually.
The main problem is that the variable arr
is of type IntArray
and IntArray
not derived from Array
. Likewise, while it IntArray
has a function iterator()
, it does not implement Iterable<>
.
The same happens for a variable CharArray
.
In fact IntArray
both CharArray
and Array<T>
and do not seem to have a common base class or interface other than Any
. So you either loop over passing an object and do a typecheck in printMe
, or you use an overload.
The type checking version would look like
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")
}
}
The overload will look like this:
printMe(args:IntArray) {
for(item in args) {
println(item)
}
}
printMe(args:CharArray) {
for(item in args) {
println(item)
}
}
Overloading is IMO the best option as you cannot end up passing an object that you cannot handle by mistake.
source to share