Jordi
Jordi

Reputation: 2537

How can I create a Kotlin class that can be used in a for loop?

I have a custom implementation of a list which returns a new item if none is contained within it.

@Parcelize
class ListOfItems(private val list: Map<String, Item> = mapOf()) : Parcelable {
    operator fun get(name: String) = list[name] ?: Item(name)
}

I'd like to use it inside for loop:

val myListOfItems = ListOfItems(/* ... */)
for (item in myListOfItems)
{
    // Do something...
}

How can I achieve it? Is there some interface that I have to implement o some method that I have to add?

Upvotes: 1

Views: 677

Answers (2)

As @Jordi noticed, you need to implement Iterable interface. This could be done even simplier:

class ListOfItems(private val list: Map<String, Item> = mapOf()) : Parcelable, Iterable<Item> by list.values {
    operator fun get(name: String) = list[name] ?: Item(name)
}

Moreover, you may implement not Iterable but Collection interface (which extends Iterable) in the same way, taking advantage of various extension members defined for Collection:

class ListOfItems(private val list: Map<String, Item> = mapOf()) : Parcelable, Collection<Item> by list.values {
    operator fun get(name: String) = list[name] ?: Item(name)
}

Or even List (to make class name consistent with its interface):

class ListOfItems(private val list: Map<String, Item> = mapOf()) : Parcelable, List<Item> by list.values.toList() {
    operator fun get(name: String) = list[name] ?: Item(name)
}

Upvotes: 3

Jordi
Jordi

Reputation: 2537

In Kotlin, for a class to be used in a for loop it must implement Iterable<T> interface.

As per your example:

@Parcelize
class ListOfItems(private val list: Map<String, Item> = mapOf()) : Parcelable, Iterable<Item> {
    operator fun get(name: String) = list[name] ?: Item(name)

    override fun iterator(): Iterator<Item> = list.values.iterator()
}

Upvotes: 2

Related Questions