Почему этот код не запускается, это ошибка в Kotlin? - PullRequest
2 голосов
/ 10 ноября 2019

Я пишу кусок кода, затем компилирую его без ошибок. но при запуске выдается исключение (java.lang.NoClassDefFoundError: TesKt $ test $ 1 $ 1).

Это языковая ошибка?

private fun test(block:()->Unit) = arrayOf(1).map {

    object {

        fun print() {
            println("Hello print")
            block()
        }
    }
}

fun main(args: Array<String>) {
    val array = test{println("Hello main")}
    array[0].print()
}

1 Ответ

1 голос
/ 10 ноября 2019

Я собираюсь заключить, что это ошибка в компиляторе Kotlin. Я много играл с этим кодом и изучал скомпилированный байт-код. Кажется, компилятор теряет некоторую информацию об анонимном классе, который определяется как object.

Если мы добавим тип к этому объекту, то он будет работать нормально:

interface Printable {
    fun print()
}

private fun test(block:()->Unit): List<Printable> {
    return arrayOf(1).map {

        object: Printable {

            override fun print() {
                println("Hello print")
                block()
            }
        }
    }
}

fun main(args: Array<String>) {
    val array = test{println("Hello main")}
    array[0].print()
}

КакВы можете видеть, я только определил простой Printable интерфейс и аннотировал анонимный класс этим интерфейсом.

Давайте назовем ваш код: версия A, а мой код: Версия B.

Я скомпилировал код A, а затем декомпилировал его в Java. Вот результат:

import TestKt.test.1.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"\u0000#\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\b\u0002\n\u0002\u0018\u0002*\u0001\b\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "TestKt$test$1$1", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<1> test(Function0<Unit> block) {
      Object[] $this$map$iv = new Integer[]{1};
      int $i$f$map = false;
      Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
      int $i$f$mapTo = false;
      Integer[] var6 = $this$map$iv;
      int var7 = $this$map$iv.length;

      for(int var8 = 0; var8 < var7; ++var8) {
         Object item$iv$iv = var6[var8];
         int it = ((Number)item$iv$iv).intValue();
         int var11 = false;
/*#31:*/ TestKt.test..inlined.map.lambda.1 var13 = new TestKt.test..inlined.map.lambda.1(block);
         destination$iv$iv.add(var13);
      }

      return (List)destination$iv$iv;
   }

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((1)array.get(0)).print();
   }
}

И это результат того же процесса для кода B:

import TestKt.test..inlined.map.lambda.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"\u0000\"\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
   d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "LPrintable;", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<Printable> test(Function0<Unit> block) {
      Object[] $this$map$iv = new Integer[]{1};
      int $i$f$map = false;
      Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
      int $i$f$mapTo = false;
      Integer[] var6 = $this$map$iv;
      int var7 = $this$map$iv.length;

      for(int var8 = 0; var8 < var7; ++var8) {
         Object item$iv$iv = var6[var8];
         int it = ((Number)item$iv$iv).intValue();
         int var11 = false;
/*#31:*/ 1 var13 = new 1(block);
         destination$iv$iv.add(var13);
      }

      return (List)destination$iv$iv;
   }

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkParameterIsNotNull(args, "args");
      List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((Printable)array.get(0)).print();
   }
}

Как вы можете видеть, единственные различия находятся в первой строке, а также строки 19, 31 и 41 (прокомментированные как #19: и т. д.).

В коде A ожидается тип (как ни странно) с именем 1. Но этот тип 1, который упакован как TestKt.test.1.1, не найден, поэтому вы получили ошибку (NoClassDefFoundError: TesKt$test$1$1).

Код Inn B, однако более понятный тип Printable ожидается и найден.

Если бы компилятор скомпилировал самую первую строку кода A точно так же, как код B (import TestKt.test..inlined.map.lambda.1; вместо import TestKt.test.1.1;), тогда ваш код работал бы.

...