我仍在学习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
工作得很好而且更简单吗?
答案 0 :(得分:1)
fun x()
是程序编程中的普通命名函数。 val y
是一个包含对x
的引用的属性。 val z
是函数式编程的匿名函数。
::
是一个&#39;函数引用&#39;,是程序和函数式编程之间的桥梁。
默认情况下,您的功能应为fun
。另一方面,Lambda表达式(匿名函数)旨在作为回调传递给其他函数。
答案 1 :(得分:0)
IF 您认为,从我的角度来看,我认为您可以立即理解。
x
只是标识符而不是变量,因此您无法直接引用它。fun x()
是一个派生自Function0
。::x
是fun 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);
}
结论: 在您的代码中,您只需打印函数返回类型,可见性修饰符和签名。