kotlin的匿名函数知识点总结
Posted wodongx123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin的匿名函数知识点总结相关的知识,希望对你有一定的参考价值。
1. 匿名函数
在kotlin中,变量的类型不仅局限于基本数据类型和引用数据类型,变量的类型也可以是匿名函数,也就是说,在kotlin中,你可以将方法像变量一样的来操作,比如当成某个方法的参数。
例1:
fun test(a: Int, b:Int): Int {
return a + b
}
fun test1(a:Int, b:(Int, Int) -> Int): Int{
return a + b(1, 2)
}
在test中,a和b都是类型为Int的参数。
在test1,b的类型是一个函数,具体一点就是,b是一个参数列表为两个int类型,返回类型为int类型的函数,所以如果我们要调用test1,就要传一个函数作为参数。而这个函数除了参数列表和返回类型被限死以外,没有任何限制,你可以做任何操作。
由于你传入的这个函数,不需要设置函数名,所以我们称之为匿名函数,不过参数名可以随意设置。
test1(1,
{ a, b -> a + b + 2}
)
//运行结果是6
看我的调用,我参数a传入的是一个Int值,参数b传入的就是一个方法。
//方法为这样
fun anonymous(a: Int, b: Int) {
return a + b + 2
}
2. 匿名函数的写法
你可能还会对匿名函数的写法有点疑问,这里就先说:
- 由于匿名函数的参数列表中的类型在定义的时候设置。我在test1方法中的变量里就明确了两个参数的类型都是Int类型。
- 我们在实例化匿名函数的时候,只要设置好参数名就行,比如上面我传入的参数,写的是 a, b。而不是 a:Int, b:Int。
- 写的时候参数列表不用加括号,函数体不用加花括号,需要多行代码直接换行就行。
- 匿名函数的返回类型也是确定的,我们在写的时候需要省略return,编译器会默认将我们的最后一行得到的值作为返回值。
如果最后一行的类型不一样,编译器就会报错test1(1, { a, b -> a + b + 2 a + b + 3 } ) // 这回输出为7
- 如果你的匿名函数,只有一个参数,那么我们在实例化这个匿名函数时,可以不用写参数名,他会自动被命名为it。
fun main(args: Array<String>) { var a = test1(1, { it+3 } ) println(a) // 5 } fun test1(a:Int, b:(Int) -> Int): Int{ return a + b(1) }
3. 函数变量
既然匿名函数可以当成某个方法参数进行传递,那我们是不是可以直接定义一个变量,这个变量的类型就是一个匿名函数呢?
当然是可以的,而且定义完之后,我们可以像调用函数一样直接调用函数变量。
函数变量的类型就是参数类型+返回类型,看下面的例子。
// 定义一个变量,类型是一个匿名函数,函数参数列表为两个Int类型,返回类型为Boolean类型
var func : (Int , Int) -> Boolean
// 给变量具体赋值,也就是决定函数体。
func = {
a,b -> a == b
}
println(func) // (kotlin.Int, kotlin.Int) -> kotlin.Boolean ,表明了该变量的类型
println(func(5, 3)) // false
3.1 匿名函数的类型推断
如果你的函数变量的参数列表为空,且返回类型是显而易见,你可以不用在声明的时候写上他们。
var func = {
var str = "hello world"
str + ", hello kotlin"
}
println(func) // () -> kotlin.String
println(func()) // hello world, hello kotlin
当然如果你的参数列表不为空,也可以在定义的时候省略,但是在实例化的时候需要将它们的类型补上。
var func = {
a:String, b:Int ->
var str = "hello world"
str + ", hello kotlin " + a + b
}
println(func) // (kotlin.String, kotlin.Int) -> kotlin.String
println(func("aa", 3)) // hello world, hello kotlin aa3
4. 匿名函数和lambda表达式的关系
匿名函数就是没有方法名没有引用的函数,而labmda表达式是一种函数的写法。
简单来说,我们刚刚写的匿名函数和函数变量,他的写法都是{},然后内部是函数的具体实现,这些就是lambda表达式。
5. 函数的引用
匿名函数可以当成某个函数的参数来传递,那么普通的函数也能传递吗?
答案是肯定的,只要用双冒号就可以将普通的方法进行引用。
fun main(args: Array<String>) {
println(test1(1, ::test)); // 直接将test作为test1的参数,输出是4
}
fun test(a: Int, b:Int): Int {
return a + b
}
fun test1(a:Int, b:(Int, Int) -> Int): Int{
return a + b(1, 2)
}
双冒号的作用就是将某个函数作为引用来传递,双冒号前面要加上对象名,后面加上方法名,如果这个类的方法就是该实例内的,可以直接用this来代替,如果this没有引用混淆的情况,甚至可以省略this。
6. 匿名函数的实际用例
那么,知道了匿名函数的具体用法,在什么情况下我们编码时会需要用到匿名函数呢?
我这里举一个kotlin自带的例子
fun main(args: Array<String>) {
val count = "HELLO WORLD".count({ char ->
char == 'L'
})
println(count)
}
这个代码的作用是,计算HELLO WORLD中L的的数量,并将其输出,其中就用到了匿名函数,我们来看一下count方法的实现。
/**
* Returns the length of this char sequence.
*/
@kotlin.internal.InlineOnly
public inline fun CharSequence.count(): Int {
return length
}
/**
* Returns the number of characters matching the given [predicate].
*/
public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) ++count
return count
}
count方法一共有两个,第一个就是我们熟知的返回长度。
第二个则是支持我们以某种方式去对字串中每个字符进行某种规则的匹配,如果匹配这个规则,count就+1。
我们传入参数就是字符的匹配规则。
我们在调用count时,传入的函数时是如果当前的字符为L,则匹配,所以就变成了计算L的数量。
7. 转Java
最后看一下我们的匿名函数在java中是如何实现的。
fun main(args: Array<String>) {
}
fun test1(a: Int, b: (Int, Int) -> Int): Int {
return a + b(1, 2)
}
转字节码再转java后,
public static final void main(@NotNull String[] args) {
}
public static final int test1(int a, @NotNull Function2 b) {
return a + ((Number)b.invoke(1, 2)).intValue();
}
看来匿名函数在java中的实现,就是一个Function类型,看看这个类型。
/** A function that takes 2 arguments. */
public interface Function2<in P1, in P2, out R> : Function<R> {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2): R
}
Function2就是一个实现了带两个参数,带一个返回类型的某个方法的接口,内部的方法就是调用该方法。
以上是关于kotlin的匿名函数知识点总结的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin函数 ⑤ ( 匿名函数变量类型推断 | 匿名函数参数类型自动推断 | 匿名函数又称为 Lambda 表达式 )