简体   繁体   English

为什么这段代码不能运行,是 Kotlin 中的一个错误吗?

[英]Why can't this code run, is it a bug in Kotlin?

I write a piece of code, then compile it with no errors.我写了一段代码,然后编译没有错误。 but when I run, it throws an exception (java.lang.NoClassDefFoundError: TesKt$test$1$1).但是当我运行时,它抛出一个异常(java.lang.NoClassDefFoundError: TesKt$test$1$1)。

Is this a language bug?这是语言错误吗?

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()
}

I'm going to conclude that it's a bug in the Kotlin compiler.我将得出结论,这是 Kotlin 编译器中的一个错误。 I played a lot with this code and looked into the compiled bytecode.我对这段代码玩了很多,并查看了编译后的字节码。 It seems the compiler is losing some information about the anonymous class which is defined by object .似乎编译器正在丢失一些有关object定义的匿名类的信息。

If we add a type to that object, then it works fine:如果我们向该对象添加类型,则它可以正常工作:

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()
}

As you can see, I only defined a simple Printable interface and annotated the anonymous class with this interface.如您所见,我只定义了一个简单的Printable接口,并使用此接口注释匿名类。

Let's call your code: version A , and this code of mine: Version B .让我们称您的代码为:版本A ,而我的这段代码为:版本B

I compiled code A and then decompiled it to Java .我编译了代码A然后将其反编译为Java Here's the result:结果如下:

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();
   }
}

And this is the result of the same process for code B :这是代码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();
   }
}

As you can see, the only differences are in the first line, as well as line numbers 19, 31 and 41 (commented like #19: and so on).如您所见,唯一的区别在于第一行,以及行号 19、31 和 41(注释如#19:等)。

In code A a type (strangely) with the name of 1 is expected.在代码A ,需要名称为1的类型(奇怪)。 But this type 1 , which is packaged as TestKt.test.1.1 , is not found and so you got your error ( NoClassDefFoundError: TesKt$test$1$1 ).但是这种打包为TestKt.test.1.1类型1没有找到,所以你得到了你的错误( NoClassDefFoundError: TesKt$test$1$1 )。

Inn code B , however, a more clear type of Printable is expected and found.但是,Inn 代码B可以预期并找到更清晰的Printable类型。

If the compiler had compiled the very first line of code A just like code B ( import TestKt.test..inlined.map.lambda.1; instead of import TestKt.test.1.1; ) then your code would have worked.如果编译器像代码B一样编译了代码A第一行( import TestKt.test..inlined.map.lambda.1;而不是import TestKt.test.1.1; ),那么你的代码就可以工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM