Lets say we have an extension function like this
fun <T> MutableList<T>.fillWith(default: T, size: Int) = apply {
if (this is ArrayList) {
ensureCapacity(size)
}
while (size < newSize) add(default)
}
Our goal here is to be able to fill any list with default value T
, but return this
so that we can continue chain other methods or maybe just assign it to a field in one expression like this val data = LinkedList<String>().fillWith("", 42)
Unfortunately our return type unsurprisingly is MutableList
is there a way to return actual most specific type? so that i could define one generic extension function but be able to do things like
val data1 : LinkedList<String> = LinkedList().fillWith("", 42)
val data2 : ArrayList<String> = LinkedList().fillWith("", 42)
CodePudding user response:
As suggested by @Pawel, you can make the function generic in the list type itself:
fun <R, T: MutableList<R>> T.fillWith(default: R, newSize: Int) : T = apply {
if (this is ArrayList<*>) {
ensureCapacity(size)
}
while (size < newSize) add(default)
}
You will then have to specify the type of the elements in your list on the call site in the constructor call, because the compiler can't infer it:
val data1 = LinkedList<String>().fillWith("", 42)
val data2 = ArrayList<String>().fillWith("", 42)
Note that you can also simply make your function return Unit
and use apply
on the call site.
Also, if you don't care that much about the specific list implementation, there are already built-in functions List() and MutableList() for the specific use case of initialization like this:
// creates a list of 42 empty strings
val list = MutableList(42) { "" }
// creates a list of 42 strings "elt 0", "elt 1" etc.
val list = MutableList(42) { index -> "elt $index" }