命名函数vs lambda反射

时间:2017-06-14 16:03:25

标签: kotlin

我仍在学习Kotlin,并试图了解其核心原则。我没有得到的是:

fun x() : Int { return 10 }
val y : () -> Int = ::x
val z : () -> Int = { 10 }

fun main(args: Array<String>) {
    println(::x) 
    println(y)   
    println(z)    
}

我们得到以下输出:

fun x(): kotlin.Int
fun x(): kotlin.Int
() -> kotlin.Int

我的问题是为什么输出不一样(我相信这些功能应该可以互换,等效)?我认为所有函数的类型应该是() -> Int。为什么我们将原始名称与函数签名(fun x)保持在一起,即使它被分配给另一个名称(y)?是否有任何语言设计原则需要功能签名的这种差异?

还有一个额外的问题 - 为什么我们需要使用运算符::。没有它就无法编译。但为什么语言设计需要这个?不会val y = x工作得很好而且更简单吗?

3 个答案:

答案 0 :(得分:1)

fun x()是程序编程中的普通命名函数。 val y是一个包含对x的引用的属性。 val z是函数式编程的匿名函数。

::是一个&#39;函数引用&#39;,是程序和函数式编程之间的桥梁。

默认情况下,您的功能应为fun。另一方面,Lambda表达式(匿名函数)旨在作为回调传递给其他函数。

答案 1 :(得分:0)

IF 您认为,从我的角度来看,我认为您可以立即理解。

  • x只是标识符而不是变量,因此您无法直接引用它。
  • fun x()是一个派生自Function0
  • 的类
  • 表达式::xfun x()类型的实例,在kotlin中称为function reference expression
  

Kotlin在语言中使功能和属性成为一等公民,并对其进行反思。

有时函数在kotlin中拥有自己的类,就像java-8 lambda表达式一样。但function reference expression无法与差异receiver一起使用。

当调用inline function后跟一个lambda时,lambda&amp;该功能将在呼叫站点内联。但是使用非内联function reference expression进行通话,只会在通话地点内联inline function

答案 2 :(得分:0)

我认为为了更好地理解字节码

  private final static Lkotlin/jvm/functions/Function0; y
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x1A
  // signature Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
  // declaration: kotlin.jvm.functions.Function0<java.lang.Integer>
  private final static Lkotlin/jvm/functions/Function0; z
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x19
  public final static main([Ljava/lang/String;)V
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "args"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 6 L1
    GETSTATIC MainKt$main$1.INSTANCE : LMainKt$main$1;
    ASTORE 1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L2
    LINENUMBER 7 L2
    GETSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
    ASTORE 1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L3
    LINENUMBER 8 L3
    GETSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
    ASTORE 1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L4
    LINENUMBER 9 L4
    RETURN
   L5
    LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x19
  public final static x()I
   L0
    LINENUMBER 11 L0
    BIPUSH 10
    IRETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x19
  // signature ()Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
  // declaration: kotlin.jvm.functions.Function0<java.lang.Integer> getY()
  public final static getY()Lkotlin/jvm/functions/Function0;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 12 L0
    GETSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
    ARETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x19
  // signature ()Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
  // declaration: kotlin.jvm.functions.Function0<java.lang.Integer> getZ()
  public final static getZ()Lkotlin/jvm/functions/Function0;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 13 L0
    GETSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
    ARETURN
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 12 L0
    GETSTATIC MainKt$y$1.INSTANCE : LMainKt$y$1;
    CHECKCAST kotlin/jvm/functions/Function0
    PUTSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
   L1
    LINENUMBER 13 L1
    GETSTATIC MainKt$z$1.INSTANCE : LMainKt$z$1;
    CHECKCAST kotlin/jvm/functions/Function0
    PUTSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
    RETURN
    MAXSTACK = 1
    MAXLOCALS = 0
}

y和z值的类型为Function0

static <clinit>()V // here we have static initialization block where y and z are initialized

x的类型为MainKt $ main $ 1

在每种情况下(println)我们只显示方法声明(可见性修饰符,返回类型,签名)而不调用。 y和z是高阶函数,在字节码中由Function0类表示,对于x值,它只是静态函数。

当您调用println(::x) println(y) println(z)时,您只需打印函数声明。这没关系,x和y函数的声明与z函数的声明不同。因为y引用了x函数,而z仍然是返回10的高阶函数。简单来说y == x,因为你从x赋值给y函数声明。 只是为了注意。在Java中,我可以用这种方式显示方法声明:

  public static void main(String[] args) {
    try {
      System.out.println(Main.class.getMethod("A", null)); // prints public static void Main.A()
    } catch (NoSuchMethodException e) {
      e.printStackTrace();
    }
  }

  public static void A() {
    System.out.println(15);
  }

结论: 在您的代码中,您只需打印函数返回类型,可见性修饰符和签名。