If I have the following code:
fun main() {
println(Example("test", 1))
}
class Example(private val text: String, private val num: Int) {
override fun toString(): String {
return "String: $text $num"
}
}
and it works.
Is there any way to do this for types different from string?
Example:
class Example {
fun toList(): List {
//Convert to list...
}
}
thisFunctionRequireList(Example2())
CodePudding user response:
I will first explain how
println(Example1())
works, and from there, create something similar.
First, note that println
has many overloads. This println
call does not call the println(String)
overload. It calls the println(Any?)
overload.
The println(Any?)
overload is implemented to transform the Any
parameter into a String
using toString
, and then calls the println(String)
overload using that string. Here is the Kotlin/Native implementation:
public actual fun println(message: Any?) {
println(message.toString())
}
Note that it is able to do this, only because Any?
, and by extension Any
, declares the toString
method. This allows it to convert any value you pass, to a String
. At runtime, this gets dispatched to the toString
override that you declared in Example1
.
Therefore, it is not because you overrode toString
, that you were able to call println
with Example
. It is because
println
has an overload that takesAny
, allowing you to pass anything into itAny
also declares atoString
that you can override, whichprintln(Any)
also uses in its implementation
Any
does not declare a toList
method, so we can't use Any
if we want to do the same for List
.
We can declare a new interface for types that can be converted to lists:
interface ConvertibleToList<T> {
fun toList(): List<T>
}
This is like an Any
, but only for types that implement it. Example2
can then implement the interface:
class Example2: ConvertibleToList<String> {
override fun toList(): List<String> {
//Convert to list...
}
}
Now suppose there is an existing function that takes a List<String>
:
fun doThingsToStrings(strings: List<String>) { ... }
You can add a new overload of this, with the parameter type being ConvertibleToList<T>
:
fun doThingsToStrings(strings: ConvertibleToList<String>) = doThingsToStrings(strings.toList())
doThingsToStrings
becomes just like println
, with one overload taking the "exact" type (List<String>
), and another overload taking types that can be converted to the "exact" type (ConvertibleToList<String>
).
Now you can call doThingsToStrings
with Example2()
!