Передать тип данных в качестве параметра функции - PullRequest
0 голосов
/ 06 ноября 2019

Я использую 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

Я также пытался Тип в качестве типа данных аргумента, но та же ошибка сохраняется. Как я могу передать DataType моему методу конвертации? Спасибо!

Ответы [ 2 ]

3 голосов
/ 06 ноября 2019

Здесь происходит несколько вещей.

Во-первых, традиционный способ передать тип - это передать его KClass объект (используя ::type) или Class object (используя ::type.class).

Таким образом, вы можете объявить свою функцию как:

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

Но это создает новую проблему: Gson().fromJson() возвращает объектуказанного вами типа. В этом случае это может быть что угодно (отсюда *), и поэтому компилятор не знает, можно ли на нем вызвать toList().

Одним из решений этого было бы дать типbound, например:

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

Это указывает, что тип, который вы передаете, должен быть некоторой реализацией Collection, и что он возвращает List с тем же типом элемента. И поскольку Collection имеет метод toList(), он все работает.

Однако это не сработает для вашего случая передачи типа Array, так как массивы не имеют toList()метод. (Array типы немного неудобны в Kotlin. Они в основном для обратной совместимости с Java; List s лучше во многих отношениях.)

Вы можете использовать вышеупомянутое, и использовать 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()

И в качестве окончательной настройки мы можем использовать другой, немного более аккуратный, способ передачи типов Котлина: сделать их реализованными. Эта замена выполняется во время компиляции, а не во время выполнения, и работает только для inline функций:

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

val model: List<MyDataModel> = convert<Array<MyDataModel>>().toList()
1 голос
/ 06 ноября 2019

Боюсь, вам придется использовать дженерики здесь:

Что-то вроде:

inline fun <T, reified R>convert( t : T ) : R {
    return Gson().fromJson(t, R::class.java )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...