Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a type to generic method in Kotlin?

I have a generic method like below

private fun <T> getSomething(): T {
    return "something" as T
}

How can I call this method with a variable T type?

val types = arrayListOf<Type>(String::class.java, Boolean::class.java)
types.forEach { type ->
    val something = getSomething<type>() // Unresolved reference: type
}

At runtime, I don't know what would be generic type T. I am getting the type from types and should pass it with generic getSomething method.

Use case

I want to call database which has several table. Example models are like this

class User{

}

class Student{

}

Since all the calling queries are basically same, I want to have generic method for calling database and get data.

private fun <T> getData(model: String): List<T>?{
    return when(model){
        "user" -> getUsers()
        "student" -> getStudents()
        else -> null
    }
}

So when I call above method. Within my loop I want to pass Type as either User or Student.

val types = arrayListOf<Type>(User::class.java, Student::class.java)
types.forEach { type ->
    val data = getData<type>(type.javaClass.simpleName) // Unresolved reference: type in <type>
}

How can I achieve it.

like image 260
musooff Avatar asked Dec 03 '18 05:12

musooff


People also ask

How do I call generic method Kotlin?

Kotlin generic example When we call the generic method <T>printValue(list: ArrayList<T>) using printValue(stringList), the type T of method <T>printValue(list: ArrayList<T>)will be replaced by String type.

How do you use the generic class in Kotlin?

Type Erasure. As with Java, Kotlin's generics are erased at runtime. That is, an instance of a generic class doesn't preserve its type parameters at runtime. For example, if we create a Set<String> and put a few strings into it, at runtime we're only able to see it as a Set.

How do you provide a parametrized type for a generic?

In order to use a generic type we must provide one type argument per type parameter that was declared for the generic type. The type argument list is a comma separated list that is delimited by angle brackets and follows the type name. The result is a so-called parameterized type.

What is out type in Kotlin?

"Out" keyword is extensively used in Kotlin generics. Its signature looks like this − List<out T> When a type parameter T of a class C is declared out, then C can safely be a super type of C<Derived>. That means, a Number type List can contain double, integer type list.


2 Answers

Here's a complete example:

import kotlin.reflect.KClass

data class User(val name: String)
data class Student(val name: String)

fun getUsers(): List<User> = listOf(User("JB"))
fun getStudents(): List<Student> = listOf(Student("Claire"))

fun <T: Any> getData(clazz: KClass<T>): List<T>? {
    return when(clazz) {
        User::class -> getUsers() as List<T>
        Student::class -> getStudents()  as List<T>
        else -> null
    }
}

fun main(args: Array<String>) {
    val types = listOf(User::class, Student::class)
    types.forEach { type ->
        val data = getData(type)
        println(data)
    }
}
like image 77
JB Nizet Avatar answered Oct 17 '22 00:10

JB Nizet


I would stick to concrete types like

import kotlin.reflect.KClass

interface IBaseData
interface IDataTable<out T> where T : IBaseData
{
    fun getData(): List<T>
}

class User : IBaseData
class Student : IBaseData

class UserTable : IDataTable<User>
{
    override fun getData(): List<User>
    {
        return listOf(User())
    }
}

class StudentTable : IDataTable<Student>
{
    override fun getData(): List<Student>
    {
        return listOf(Student())
    }
}

inline fun <reified T: IBaseData> getDataTable() : IDataTable<T>?
{
    return when(T::class)
    {
        User::class -> UserTable() as IDataTable<T>
        Student::class -> StudentTable() as IDataTable<T>
        else -> null
    }
}

fun main()
{
    var user = getDataTable<User>()?.getData()
    var student = getDataTable<Student>()?.getData()
}

But still, it's an overhead, why not to use getUser() or getStudents() directly

like image 23
Dmitry Avatar answered Oct 17 '22 00:10

Dmitry