Kotlin知识总结:高阶函数

定义

高阶函数是将函数用作参数或返回值的函数。在java中,函数是不可以作为参数或者返回值的,所以要实现这样的功能,会使用接口来中转,比如:

public interface Wrapper {
  int method(int param);
}

int a(Wrapper wrapper) {
  return wrapper.method(1);
}
a(wrapper1);
a(wrapper2);

在Kotlin中,函数是可以作为参数的

fun a(funParam: (Int) -> String): String {
  return funParam(1)
}

可以作为返回值

fun c(param: Int): (Int) -> Unit {
  ...
}

如果要把函数赋值给一个对象,要使用双":",

val d = ::b

双冒号的写法叫做函数引用 Function Reference,将函数变成对象,「函数可以作为参数」的本质,是函数在 Kotlin 里可以作为对象存在,因为只有对象才能被作为参数传递。在 Kotlin 里,一个函数名的左边加上双冒号,它就不表示这个函数本身了,而表示一个对象,或者说一个指向对象的引用,这个对象不是函数本身,而是一个和这个函数具有相同功能的对象

b(1) // 调用函数
d(1) // 用对象d 后面加上括号来实现 b() 的等价操作,实际上会调用 d.invoke(1)
(::b)(1) // 用对象 :b 后面加上括号来实现 b() 的等价操作,实际上会调用 (::b).invoke(1)

使用:

fun num1AndNum2(num1: Int, num2: Int, method: (a: Int, b: Int) -> Int): Int {
    return method(num1, num2)
}

fun plus(num1: Int, num2: Int): Int {
    return num1 + num2
}
//三种不同的调用方法
  var num1 = 10
  var num2 = 20
  var result1 = num1AndNum2(num1, num2, ::plus)
  println(result1)

   var result2 = num1AndNum2(num1, num2, fun(num1: Int, num2: Int): Int {
        return num1 - num2
    })
    println(result2)
//如果 Lambda 是函数的最后一个参数,可以把 Lambda 写在括号的外面,
 var result3 = num1AndNum2(num1, num2) { a, b ->
        a + b
    }
    println(result3)

关于lambda的几点说明
如果 Lambda 是函数的最后一个参数,可以把 Lambda 写在括号的外面

view.setOnClickListener() { v: View ->
  switchToNextPage()
}

如果 Lambda 是函数唯一的参数,可以直接把括号去掉

view.setOnClickListener { v: View ->
  switchToNextPage()
}

如果 Lambda 是单参数的,这个参数可以省略掉不写

view.setOnClickListener {
  switchToNextPage()
}

如果用到这个参数,然后没写,可以使用it,Kotlin 的 Lambda 对于省略的唯一参数有默认的名字:it

view.setOnClickListener {
  switchToNextPage()
  it.setVisibility(GONE)
}

Lambda 的返回值不是用 return 来返回,而是直接取最后一行代码的值

val b: (Int) -> String = {
  it.toString() // it 可以被推断出是 Int 类型
}

如果写了return,会把这个作为它外层的函数的返回值来直接结束外层函数。return 从最近的使用 fun 关键字声明的函数返回, lambda 表达式没有使用 fun关键字,所以 lambda 中的 return 从最外层的函数返回

内联函数

每调用一次 lambda 表达式,一个额外的类就会被创建。如果 lambda 捕捉了某个变量,那么每次调用的时候都会创建一个新的对象 。这就会带来额外的开销。如果使用 inline 修饰符标记一个函数,在函数被使用的时候编译器并不会生成函数调用的代码,而是使用函数实现的真实代码替换每一次的函数调用。这样的函数就是内联函数,用于定义重复调用的函数,减少开销。
使用inline 关键字只能提高带有 lambda 参数的函数的性能,其他的情况需要额外的度量和研究。应该注意代码的长度。如果要内联的函数很大,将它的字节码拷贝到每一个调用点将会极大地增加字节码的长度。

inline fun doCal(a: Int, b: Int, cal: (a: Int, b: Int) -> Int): Int {
  return cal(a, b)
}

如果希望只内联一部分传给内联函数的 lambda 表达式参数, 那么可以用 noinline 修饰符标记不希
望内联的函数参数:

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { …… }

参考:Kotlin 的 Lambda 表达式

你可能感兴趣的:(kotlin,高阶函数)