函数类型

2018-07-25  本文已影响0人  一江碎月

用于指定该参数接收一个函数或者一个 lambda 表达式。

声明

用小括号将参数类型括起来,后跟 ->,最后是返回值类型。如下:

(Int,String, Int) -> Unit

它表示该函数接收三个参数,类型分别是 int,string,int,返回值类型为 Unit。因此,下面定义的函数可以匹配上述的函数类型:

    fun demo(a: Int, b: String, c: Int) 

函数类型的参数可以接收一个 labmda 或 一个函数成员引用,不能直接将函数名传入其中

fun main(args: Array<String>) {
    test(::demo)

    test { a, b, c ->
        println("$a,$b,$c")
    }
}

fun test(action: (Int, String, Int) -> Unit) {
    action(3, "aaa", 2)
}

fun demo(a: Int, b: String, c: Int) {
    println("$a,$b,$c")
}

函数类型接口

函数类型是一种类型,因此函数类型可以做为父类,可以定义实现了某个函数类型的类。

函数类型的子类,必须重写 invoke 方法。该方法的参数类型是函数类型的参数类型,返回值类型是函数类型的返回值类型:

fun main(args: Array<String>) {
    val t = Test()
    println( t("xxx")) // true
    println(t("yii")) // false
}

class Test : (String) -> Boolean {
    override fun invoke(p1: String): Boolean = p1.contains("xx")
}

在编译后,函数类型会转成 Function 的子类,而 Function 中定义了 invoke 方法,所以子类必须实现 invoke 方法。

而且根据 invoke 约定,可直接使用像调用函数一样调用子类实例。如上述的 t("xxx")。


实质

函数类型在编译后都会转成 FunctionN<P1,P2,...,PN,R> 的子类。其中 P1 到 PN 表示函数类型的参数类型,R 表示返回值类型。因此,(T)->R 可以认为是 Function1 类的 kt 写法,两者等价。

默认值

函数类型也是一种类型,因此可以用作函数的形参类型。

kt 的函数中,形参可以指定默认值。因此函数类型的形参也可以指定默认值,其值可以是成员引用,也可以是 lambda:

fun main(args: Array<String>) {
    println(demo())
    println(demo2())
}

fun test() = "aa"

fun demo(a: () -> String = { "lambda" }) = a()
fun demo2(a: () -> String = ::test) = a()

作为参数,表达式有可能为 null,只要对应的变量声明为可空类型。而 java 调用含 lambda 的函数时,在对应的位置上传递的是 FunctionN 的实例。 而 FunctionN 中定义了 invoke 方法,因此可以 结合 FunctionN 与安全调用,避免对参数的空判断

fun test(a:((Int)->String)?){
    if(a != null)
        println(a(2))
}

fun test2(a:((Int)->String)?){
    println(a?.invoke(3)) // 直接调用 invoke 方法,相当于执行了表达式
}

test() 方法中进行空判断,然后调用;test2 中,使用安全调用 invoke 方法。


在 java 中使用

在 java 中调用含有函数类型参数的函数时,需要显式地传入一个 FunctionN 的实例。

一个函数类型的变量是 FunctionN<> 接口的一个实现。其中 N 表示函数需要的参数个数,泛型依次为参数类型及返回值类型。

FunctionN 中有一个 invoke 方法,该方法中可以写入 lambda 的主体。

如下,调用函数类型为 (Int)->Unit 的 test 函数时,需要传入一个 Function1 的实例。因为表达式需要返回一个 Unit 类型的实例,该类型的实例只有 Unit.INSTANCE 一个,因此在 Java 中调用时需要显式返回:

        DemoKt.test(new Function1<Integer, Unit>() {
            @Override
            public Unit invoke(Integer integer) {

                return Unit.INSTANCE;
            }
        });
上一篇 下一篇

猜你喜欢

热点阅读