Kotlin learning之Lambda表达式

Lambda表达式

高阶函数

所谓高阶函数就是把函数当作参数传递或者返回值的函数。

函数类型的声明

我们来看一下实际的例子:

fun main() {
   
    println(f(1, 2, {
    a, b -> a + b }))
    println(f(1, 2, {
    a, b -> a - b }))


}

fun f(i: Int, j: Int, op: (Int, Int) -> Int): Int {
   
    return op(i, j)
}

// output:3
// output:-2

这里的f函数是一个高阶函数,它有三个参数,一个是分别是i、j、和op,i和j都是Int类型,而op是一个函数类型,我们看下它的类型声明( Int, Int) -> Int,括号里的Int是函数类型声明的参数,-> Int这里的Int指的是函数类型的返回值。那么这个函数参数的意义就是通过两个Int值的某些操作返回一个Int值。而这个所谓的某些操作就是我们要具体传递的方法。例如{ a, b -> a + b }表示将两个Int值相加。{ a, b -> a - b }表示将两个数相减。

所有的函数类型都会有一个括号括起来的参数类型列表和返回类型。比如(A, B) -> C表示一个函数需要传递两个参数,类型分别是A和B,返回值类型是C。参数类型可以省略,但是返回值类型不能省略。如() -> Unit
函数类型可以额外有一个接受者类型。例如这个定义:A.(B) -> C,表示这个函数可以被A类型调用,参数是B类型,返回值是C类型。在这个函数内部可以直接通过this访问A类的属性或者方法,甚至直接省略this

函数类型也有几个特殊的例子:

  • (Int, Int) -> Int?表示参数类型是Int,返回值类型是Int?
  • ((Int, Int) -> Int)?表示参数类型是Int,返回值类型是Int,但是整个函数可以为null
  • (Int) -> ((Int) -> Unit)表示参数类型是Int,返回值类型是另外一个函数类型,而这个函数类型的参数是Int,返回值类型是Unit
  • (Int) -> (Int) -> Unit的箭头优先级的顺序是从右向左,也就是它等价于(Int) -> ((Int) -> Unit)

函数类型的初始化

有以下几种方式获取一个函数类型的实例:

  1. 通过lambda表达式{ a, b -> a + b }
  2. 通过一个匿名函数fun(s: String): Int { return s.toIntOrNull() ?: 0 }
  3. 通过一个引用已经存在的声明String::toInt
  4. 如果类实现了将函数类型接口,可以使用这个类的实例,例如:
class IntTransformer: (Int) -> Int {
   
    override operator fun invoke(x: Int): Int = TODO()
}

val intFunction: (Int) -> Int = IntTransformer()

函数类型的引用

可以通过invoke方法调用,或者直接调用。举个例子:

    fun main() {
   
        val intPlus: (Int, Int) -> Int = {
    a, b -> a + b }
    
        intPlus.invoke(2,3)
        intPlus(4,5)
        
    }

如果是带接受者的函数类型,可以把接受者作为第一个参数调用或者将接受者放在括号外类似于扩展函数的方式调用。例如:

import java.lang.StringBuilder

fun main() {
   
    // 将string复制n份
    val stringPlus: String.(Int) -> String = {
    it ->
        var count = it
        val builder = StringBuilder()
        while (count-- > 0) {
   
            builder.append(this)
        }
        builder.toString()
    }

    println("abs".stringPlus(3))
    println(stringPlus("xyz",5))
    println(stringPlus.invoke("mnp",4))

}
// output:
// absabsabs
// xyzxyzxyzxyzxyz
// mnpmnpmnpmnp

将Lambda表达式传递给java方法

我们知道java中的部分匿名内部类在kotlin中可以使用lambda来表示,那么lambda表达式对应的java code是不是就是一个匿名内部类呢?
我们来看几个例子:

假设我们定义了一个java 接口和设置这个接口的方法:

public interface OnClickListener {
   
    void onClick();
}
public class HelloJava {
   
    public  void setListener(OnClickListener onClickListener){
   

    }
}

现在在Kotlin中调用这个setListener方法:

fun main() {
   
    var s = "sss"
    // 1
    HelloJava().setListener {
    println("hi") }
    // 2
    HelloJava().setListener {
    println("hi") }
    // 3
    HelloJava().setListener {
    print("$s") }
    // 4
    HelloJava().setListener(object : OnClickListener {
   
        override fun onClick() {
   
            println("hi")
        }

    })
}

1、2、3都是使用lambda的方式,而4是使用匿名内部类的方法。
来看下这四种方法对应的java code:

 public static final void main() {
   
      final ObjectRef s = new ObjectRef();
      s.element = "sss";
      // 1
      (new HelloJava()).setListener((OnClickListener)null.INSTANCE);
      // 2
      (new HelloJava()).setListener((OnClickListener)null.INSTANCE);
      // 3
      (new HelloJava()).setListener((OnClickListener)(new OnClickListener() {
   
         public final void onClick() {
   
            String var1 = String.valueOf((String)s.element);
            System.out.print(var1);
         }
      }));
      // 4
      (new HelloJava()).setListener((OnClickListener)(new OnClickListener() {
   
         public void onClick() {
   
            String var1 = "hi";
            System.out.println
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值