Реализованная встроенная функция для массивов - PullRequest
0 голосов
/ 27 сентября 2018

Возможно ли в Kotlin написать встроенную функцию с reified-типом, которая может возвращать различные виды Arrays?Я думаю о чем-то вроде этого:

inline fun <reified E> getArray(key: String, defValue: Array<E>): Array<E>? {
    return when(defValue) {
        is Array<Int> -> // ...
        is Array<String?> -> // ...
        else // ...
    }
}

И я хотел бы назвать это так:

fun intArray(size: Int): Array<Int> = Array(size) {i -> 0}
fun stringArray(size: Int): Array<String?> = Array(size) {i -> null}

val strings: Array<Int> = getArray(KEY_INTS, intArray(0))
val strings: Array<String> = getArray(KEY_STRINGS, stringArray(0))

Но с этим я получаю ошибку:

Не удается найти проверку для экземпляра стертого типа

1 Ответ

0 голосов
/ 27 сентября 2018

Явно отвечая на вопрос - Вы можете использовать его, проверив класс E:

inline fun <reified E: Any> getArrayInline(key: String, defValue: Array<E>): Array<E>? {
    return when(E::class) {
        Int::class -> arrayOf(1, 2, 3)
        String::class -> arrayOf("a", "b", "c")
        else -> throw IllegalArgumentException("Invalid class: ${E::class.qualifiedName}")
    } as Array<E>
}

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

  1. Это небезопасно - вывыполнять небезопасное приведение к результату, и его можно вызывать для любого типа массива, даже если он не включен в when падежей
  2. , он встроен - поэтому весь этот блок кода копируется в байт-код всякий раз, когда вы используетеметод (см. ниже)
  3. проверка типов выполняется во время выполнения, поэтому он снижает производительность

Что происходит при его использовании?Давайте проверим этот пример:

fun testArrayInline(){
    val test = getArrayInline("key", emptyArray<Int>())
    val test2 = getArrayInline("key2", emptyArray<String>())
}

Просто верно?Но как только вы посмотрите на сгенерированный байт-код, это не так хорошо.Для удобства чтения это байт-код Kotlin, декомпилированный обратно в Java:

public static final void testArrayInline() {
  String var1 = "key";
  Object[] defValue$iv = new Integer[0];
  KClass var3 = Reflection.getOrCreateKotlinClass(Integer.class);
  Object var10000;
  if (Intrinsics.areEqual(var3, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
     var10000 = new Integer[]{1, 2, 3};
  } else {
     if (!Intrinsics.areEqual(var3, Reflection.getOrCreateKotlinClass(String.class))) {
        throw (Throwable)(new IllegalArgumentException("Invalid class: " + Reflection.getOrCreateKotlinClass(Integer.class).getQualifiedName()));
     }

     var10000 = new String[]{"a", "b", "c"};
  }

  Integer[] test = (Integer[])((Object[])var10000);
  String var7 = "key2";
  Object[] defValue$iv = new String[0];
  KClass var4 = Reflection.getOrCreateKotlinClass(String.class);
  if (Intrinsics.areEqual(var4, Reflection.getOrCreateKotlinClass(Integer.TYPE))) {
     var10000 = new Integer[]{1, 2, 3};
  } else {
     if (!Intrinsics.areEqual(var4, Reflection.getOrCreateKotlinClass(String.class))) {
        throw (Throwable)(new IllegalArgumentException("Invalid class: " + Reflection.getOrCreateKotlinClass(String.class).getQualifiedName()));
     }

     var10000 = new String[]{"a", "b", "c"};
  }

  String[] test2 = (String[])((Object[])var10000);
}

Это довольно много, учитывая, что функция была вызвана только дважды с двумя случаями в блоке «когда».И это даже не делает ничего полезного - вы уже можете видеть результат if случаев.


Правильный способ сделать это - объявить каждый тип как отдельный невстроенные функции:

fun getArray(key: String, defValue: Array<Int>) : Array<Int>{
    return arrayOf(1, 2, 3)
}

fun getArray(key: String, defValue: Array<String>) : Array<String>{
    return arrayOf("a", "b", "c")
}

Вы должны написать немного больше кода, но у него нет ни одной из 3 проблем, которые я упомянул выше.

Таким же образом вы получаете очень чистый байт-код (небольшой размер, высокая производительность), это декомпилированный байт-код того же примера, что и раньше, но с использованием не встроенных функций:

public static final void testArray() {
  String var3 = "key";
  Integer[] var4 = new Integer[0];
  getArray(var3, var4);
  var3 = "key2";
  String[] var5 = new String[0];
  getArray(var3, var5);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...