在Kotlin中,函数类型如 () -> Unit
或 (Int, String) -> Boolean
实际上是一些特别的接口。它们界说了一个 invoke
办法。
举例来说,关于一个无参数和无回来值(Unit)的函数类型 () -> Unit
,其完成的接口是这样的:
interface Function0<out R> : Function<R> {
public operator fun invoke(): R
}
关于下边这段代码:
var method01 : (() -> Unit)?= null
fun main() {
"Derry".shows()
"2353453".shows()
if (method01 != null) {
method01()
}
method01?.invoke() // 调用函数
}
它反编译之后的内容是:
public final class Lambda00Kt {
@Nullable
private static Function0 method01;
@Nullable
public static final Function0 getMethod01() {
return method01;
}
public static final void setMethod01(@Nullable Function0 var0) {
method01 = var0;
}
public static final void main() {
Lambda01Kt.shows("Derry");
Lambda01Kt.shows("2353453");
if (method01 != null) {
method01.invoke();
}
Function0 var10000 = method01;
if (var10000 != null) {
Unit var0 = (Unit)var10000.invoke();
}
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
可见无论是()仍是invoke,终究的调用都是Function0的invoke函数。当你声明一个 () -> Unit
类型的变量并赋予一个函数或者lambda表达式,你实际上是创建了一个 Function0<Unit>
类型的目标,这个目标有一个 invoke
办法。
在 Kotlin 中,invoke
是一个特别的操作符函数。假如类型界说了 invoke
操作符函数,那么该类型的实例能够经过在实例名后边跟 ()
来调用 invoke
函数。这便是为什么你能够经过 ()
来 “调用” 函数类型的实例,例如 method01()
。
这便是为什么 ()
和 invoke()
在这种情况下等价的原因:它们实际上都是调用了 invoke
办法。
可是要注意,这只对那些界说了 invoke
操作符函数的类型适用。并不是一切的 Kotlin 类型都界说了 invoke
操作符函数,关于那些没有界说 invoke
操作符函数的类型,是不能经过 ()
来 “调用” 实例的。
带有拓展函数的lambda
fun main() {
"Derry".shows()
"2353453".shows()
val method20 : Int.(Int) -> String = { "两数相加的成果是:${this + it}" }
println(1.method20(100))
println(method20(1, 100))
println(method20.invoke(10,200000))
}
反编译之后的代码:
public final class Lambda00Kt {
public static final void main() {
Lambda01Kt.shows("Derry");
Lambda01Kt.shows("2353453");
Function2 method20 = (Function2)null.INSTANCE;
Object var1 = method20.invoke(1, 100);
System.out.println(var1);
var1 = method20.invoke(1, 100);
System.out.println(var1);
var1 = method20.invoke(10, 200000);
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
可见,终究的调用,仍是经过invoke函数来进行完成。
函数回来一个函数
fun s04() : () -> Boolean = { true } // () -> Boolean
在 Kotlin 中,函数是不可变的。一旦函数被界说,其完成就不能改变。不能像修正变量那样去修正函数的完成。
假如你想改变 s04
的完成,需求从头界说一个新的 s04
函数,掩盖原有的函数界说。在 Kotlin 中,这能够经过使用不同的上下文(例如不同的类或文件)来完成。可是,关于同一个上下文,不能有两个同名的函数,因而不能直接重写 s04
。
可是,假如是在某个类中界说 s04
,你能够使用 open/override 机制来完成重写。下面是一个比如:
open class A {
open fun s04(): () -> Boolean = { true }
}
class B : A() {
override fun s04(): () -> Boolean = { false } // 重写 s04 的完成
}
在上面的比如中,B
类重写了 A
类中的 s04
函数。但请注意,需求使用 open
关键字来符号想要重写的函数,以清晰表示该函数能够被重写。
假如只是想改变 s04
回来的函数,你能够将 s04
界说为一个变量,然后修正这个变量的值:
var s04: () -> Boolean = { true } // 初始化为回来 true 的函数
s04 = { false } // 然后修正为回来 false 的函数
在上面的代码中,s04
是一个变量,其类型是 () -> Boolean
。你能够修正 s04
的值,从而改变 s04
回来的函数。
函数调用函数
fun s04() : (CharSequence) -> Boolean = { true } // () -> Boolean 函数回来一个函数
println(s04()("11111"))
s04()?.invoke("11111") // 该方法也能够。
在代码中,s04
是一个函数,这个函数回来另一个函数,这个回来的函数承受一个 CharSequence
参数,并回来一个 Boolean
值。
fun s04() : (CharSequence) -> Boolean = { true }
这一行界说了 s04
函数。它没有参数,回来类型是 (CharSequence) -> Boolean
,也便是一个函数类型,这个函数类型承受一个 CharSequence
参数并回来一个 Boolean
值。{ true }
是函数体,它回来的是一个lambda表达式,这个lambda表达式总是回来 true
。
所以,当调用 s04()
时,会得到一个函数,这个函数承受一个 CharSequence
参数并回来一个 Boolean
值。
然后,能够对这个函数再次调用,传入一个 CharSequence
参数。这便是为什么能够写 s04()("11111")
,由于 s04()
回来的是一个函数,然后又调用了这个函数,传入了 "11111"
作为参数。
println(s04()("11111"))
这一行的意思是:调用 s04
函数得到一个新的函数,然后调用这个新的函数,传入 "11111"
作为参数,并打印这个函数调用的成果。由于 s04
回来的函数总是回来 true
,所以这行代码终究会打印 true
。
函数被界说之后就不能修正他的界说了,所以假如用以下的写法,是过错的:
fun s04() : (() -> Boolean ) ? = null// () -> Boolean 函数回来一个函数
s04 = { true }
但能够这么写:
var s04 : (() -> Boolean)? = null
或者这样写:// val s04:Function1<Unit, Boolean> ?= null
s04 = { true }
下边这个是一个过错的示例,这种方法很不好,不要这么写:
val methodX1 :(String)->Int = fun(str) : Int {
return (str.length)
}
一些区别:
// fun aa{} 与 var aa={}有啥区别
fun aa() {}
var aa2 = {}
// aa便是一个函数,实打实的函数
// aa2 是接收一个匿名函数的变量而已,这个变量 能够履行这个匿名函数
// 共同点:他们现象是一样的
var aa3 = aa2 // 都属于函数引证的概念
var aa4 = ::aa // 实打实的函数 变成 函数引证 所以能够传递赋值 给另外一个变量
函数的函数的函数的函数的嵌套示例,这也是kotlin的lambda的精髓所在:
例1:
var k01 : ((String)->(CharSequence)->(Long)->(Short)->(Float)->Int)? = null
k01 = {
{
{
{
{
1
}
}
}
}
}
例2:
fun show(n1:Int, lambda:(Int, Int)->Unit, n2:Int) = lambda(n1, n2)
// 调用 show 函数,并传入一个 lambda,该 lambda 打印两个参数的和
show(5, { a, b -> println(a + b) }, 3)