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. 匿名函数的写法

你可能还会对匿名函数的写法有点疑问,这里就先说:

  1. 由于匿名函数的参数列表中的类型在定义的时候设置。我在test1方法中的变量里就明确了两个参数的类型都是Int类型。
  2. 我们在实例化匿名函数的时候,只要设置好参数名就行,比如上面我传入的参数,写的是 a, b。而不是 a:Int, b:Int。
  3. 写的时候参数列表不用加括号,函数体不用加花括号,需要多行代码直接换行就行。
  4. 匿名函数的返回类型也是确定的,我们在写的时候需要省略return,编译器会默认将我们的最后一行得到的值作为返回值。
    test1(1,
          { a, b ->
              a + b + 2
              a + b + 3
          }
    )
    // 这回输出为7
    
    如果最后一行的类型不一样,编译器就会报错
    在这里插入图片描述
  5. 如果你的匿名函数,只有一个参数,那么我们在实例化这个匿名函数时,可以不用写参数名,他会自动被命名为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就是一个实现了带两个参数,带一个返回类型的某个方法的接口,内部的方法就是调用该方法。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Kotlin中,匿名函数是一种没有名称的函数定义方式。它可以作为函数参数传递,并且能够引用定义在其作用域之外的变量。匿名函数可以使用关键字"fun"来定义,并且可以有多个参数和返回类型。 下面是一个示例,展示了匿名函数的不同定义方式: ```kotlin // 普通的匿名函数 val add = fun(x: Int, y: Int): Int { return x + y } // 简写的匿名函数 val subtract = fun(x: Int, y: Int) = x - y ``` 在上面的例子中,我们定义了两个匿名函数,一个是add函数用于求和,另一个是subtract函数用于相减。这两个函数可以像普通函数一样被调用和使用。 同时,匿名函数还可以通过引用在其作用域之外的变量。这意味着在匿名函数内部,可以访问定义在其外部函数内的变量,如下所示: ```kotlin fun sayHello(name: String): () -> Unit { val message = "Hello, $name!" return fun() { println(message) } } val hello = sayHello("John") hello() // 输出:Hello, John! ``` 在上面的例子中,我们定义了一个sayHello函数,它返回一个匿名函数,这个匿名函数可以访问sayHello函数内部定义的message变量。通过调用返回的匿名函数,我们可以打印出正确的问候语。 值得注意的是,匿名函数和Lambda表达式都可以称为函数字面值(Function Literals)。它们在使用方式上有一些差异,但本质上都是指一段没有名称的函数体或代码块。它们的灵活性使得Kotlin可以更好地支持函数式编程风格。 希望这个解答能够帮助到你,如果还有其他问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值