首页 > 解决方案 > 将数据类型作为参数传递给函数

问题描述

我正在使用 GSON 通过以下方式解析 JSON:

var obj = Gson().fromJson( json, Array<MyDataModel>::class.java ).toList()

我希望能够通过以下方式通过方法传递数据类型:

fun convert( t : Any ) : Any
{
    return Gson().fromJson( mockedResponse, t ).toList()
}

val model = convert( Array<MyDataModel>::class.java )

但我得到:

None of the following functions can be called with the arguments supplied

我也尝试将Type作为参数数据类型,但同样的错误仍然存​​在。如何将 DataType 传递给我的转换方法?谢谢!

标签: kotlinreflection

解决方案


这里发生了几件事。

首先,传递类型的传统方式是传递其KClass对象(using ::type)或Class对象(using ::type.class)。

所以你可以将你的函数声明为:

fun convert(t: Class<*>): Any

但这会产生一个新问题:Gson().fromJson()返回您指定类型的对象。在这种情况下,它可以是任何东西(因此是*),因此编译器不知道您是否可以调用toList()它。

对此的一种解决方案是提供类型绑定,例如:

fun <T: Collection<U>, U> convert(t: Class<T>): List<U>

这指定您传递的类型必须是 的某个实现Collection,并且它返回List具有相同元素类型的 a。因为Collection有一个toList()方法,所以一切都有效。

但是,这不适用于您传递Array类型的情况,因为数组没有toList()方法。(Array类型在 Kotlin 中有点尴尬。它们主要是为了向后兼容 Java;Lists 在很多方面都更好。) 

您可以使用上述内容,并直接使用 List 类型。但是,您将无法指定 List 元素类型:

fun <T: Collection<U>, U> convert(t: Class<T>): List<U> {
    return Gson().fromJson(mockedResponse, t).toList()
}

val model: List<*> = convert(List::class.java)

所以最好toList()在你的函数中删除,而不是限制类型。这样,调用者可以进行任何需要的转换,从而保留元素类型:

fun <T> convert(t: Class<T>): T {
    return Gson().fromJson(mockedResponse, t)
}

val model: List<MyDataModel> = convert(Array<MyDataModel>::class.java).toList()

作为最后的调整,我们可以使用 Kotlin 的另一种更简洁的方式来传递类型:使它们具体化。这种替换是在编译时完成的,而不是在运行时完成的,并且只适用于inline函数:

inline fun <reified T> convert(): T {
    return Gson().fromJson(mockedResponse, T::class.java)
}

val model: List<MyDataModel> = convert<Array<MyDataModel>>().toList()

推荐阅读