Consider the following interface
interface EntityConverter<in A, out B> {
fun A.convert(): B
fun List<A>.convert(): List<B> = this.map { it.convert() }
}
I want to use it in a spring boot application where specific implementations get injected so that the extension function becomes usable on the type.
However this doesn't work. The compiler does not resolve the extension function.
CodePudding user response:
Note that you're defining extension functions that are also member functions of the EntityConverter
type. You should take a look at this part of the doc for information about how this works.
Essentially, in order to use them, you need 2 instances in scope:
- the dispatch receiver (an instance of
EntityConverter<A, B>
) - the extension receiver (an instance of
A
orList<A>
, whereA
matches the first type parameter of theEntityConverter
in scope)
You can use with() to bring the EntityConverter
in scope so you can use convert
on your other instances using the usual .
syntax:
val converter = object : EntityConverter<Int, String> {
override fun Int.convert() = "#$this"
}
val list = listOf(1, 2, 3)
val convertedList = with(converter) {
list.convert()
}
println(convertedList) // prints [#1, #2, #3]
Now you have to decide whether this kind of usage pattern is what makes most sense for your use case. If you'd prefer more "classic" calls without extensions (converter.convert(a)
returning a B
), you can declare your functions as regular methods taking an argument instead of a receiver.
Bonus: functional interface
As a side note, if you add the fun
keyword in front of your EntityConverter
interface, you can create instances of it very easily like this:
val converter = EntityConverter<Int, String> { "#$this" }
This is because your converter interface only has a single abstract method, making it easy to implement with a single lambda. See the docs about functional interfaces.
CodePudding user response:
I'm not sure if you can mention extension functions as a part of interface, because it's like static functions.
I'd recommend to put "common" function in interface with A
typed parameter. Then just put extension method for list nearby.
interface EntityConverter<in A, out B> {
fun convert(a: A): B
}
fun <A, B> EntityConverter<A, B>.convert(list: List<A>): List<B> = list.map { convert(it) }
Update
I wasn't aware about possibility of inheritance of extension methods in Kotlin. And about its overriding as well. So my answer could be just an alternative of using extension methods.