将数据类型作为参数传递给函数

时间:2019-11-06 09:26:22

标签: kotlin reflection

我正在使用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传递给我的convert方法?谢谢!

2 个答案:

答案 0 :(得分:4)

这里发生了几件事。

首先,传递类型的传统方法是传递其KClass对象(使用::typeClass对象(使用::type.class)。

因此您可以将函数声明为:

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

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

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

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

这指定您传递的类型必须是Collection的某种实现,并且它返回具有相同元素类型的List。而且由于Collection有一个toList()方法,所以一切正常。

但是,这不适用于您传递Array类型的情况,因为数组没有toList()方法。 ({Array类型在Kotlin中有点尴尬。它们主要是为了与Java向后兼容; 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()

答案 1 :(得分:1)

恐怕您将不得不在此处使用泛型:

类似的东西:

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