【问题标题】:How to pass a type to generic method in Kotlin?如何将类型传递给 Kotlin 中的泛型方法?
【发布时间】:2021-06-06 08:20:30
【问题描述】:

我有一个像下面这样的通用方法

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

如何使用变量T 类型调用此方法?

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

在运行时,我不知道什么是泛型类型T。我从types 获取类型,应该使用通用getSomething 方法传递它。

用例

我想调用有几个表的数据库。示例模型是这样的

class User{

}

class Student{

}

由于所有的调用查询基本相同,我希望有一个通用的方法来调用数据库和获取数据。

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

所以当我调用上述方法时。在我的循环中,我想将Type 作为UserStudent 传递。

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>
}

我怎样才能实现它。

【问题讨论】:

  • 从你上面的例子中,你没有传递类型,而是返回类型。你到底想要什么??
  • 为什么要用“变量类名”来称呼它?你想用它做什么?由于泛型只能用于静态类型检查,并且根据定义,变量不是静态的,因此对变量泛型类型无能为力。 (一个例外是内联函数上的 reified 泛型类型,但您没有使用它)
  • @ErwinBolwidt 它不必是“变量类名”。我稍微编辑了这个例子。所以我有类列表,我必须将类型从那里传递给getSomething 方法。如果reified 可以,我该怎么办?
  • 你想用这个做什么?您想对需要此功能的something 做什么?请在您的代码中显示。
  • @ErwinBolwidt 我举了一个例子,希望能解释我想做什么

标签: generics kotlin parameter-passing generic-type-argument


【解决方案1】:

这是一个完整的例子:

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)
    }
}

【讨论】:

  • 那么您的 val 数据将为 List,并且必须猜测它必须转换为哪种类型以供进一步使用。那有什么意义呢?
  • 你应该问 OP,而不是我。但是你只会在这样的循环中拥有它,无论类型是什么,你都想做同样的事情。如果您知道类型并使用 getData(Student::class),您将获得 List,而不是 List
  • 我在 Idea 中检查过 - 在您的情况下,val 数据是 List
  • 不,是 List?所以呢?正如我所说,在这里,无论类型是什么,您都想做同样的事情,而您不知道实际的类型。如果你这样做,并使用val data = getData(Student::class),你会得到一个 List?.
  • > 使用 val data = getData(Student::class),你得到一个 List?是的,你是对的但是如果你知道类型并明确设置它,它与直接调用“getStudents”有什么不同?
【解决方案2】:

我会坚持使用具体类型,例如

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()
}

但是,这仍然是一个开销,为什么不直接使用getUser()getStudents()

【讨论】:

  • 我在这里Modularising to create a function with variable Types in Kotlin也有类似的问题。你能帮忙吗?
  • 嗯...我对数据库有同样的问题,同样类型的表具有相同的数据类型。这里的问题是 getUsers 和 getStudents 方法,它们是同一种类型,代码的好处是使这些方法具有一个类型的泛型。这个解决方案和上面一个问题一样,我们仍然需要编写单独的 getUsers 和 getStudents 方法,这是开销,所以似乎没有解决方案来简化代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 2010-11-15
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
相关资源
最近更新 更多