参数列表中的参数类型 -> 返回类型
举例:
package com.work.section //定义计算长方形面积函数 //函数类型: (Double, Double) -> Double fun rectangleArea(width: Double, height: Double): Double { return width * height } //定义计算三角形面积函数 //函数类型: (Double, Double) -> Double fun triangleArea(bottom: Double, height: Double) = 0.5 * bottom * height //函数类型: ()->Unit fun sayHello() { print("Hello, World") } fun main(args: Array<String>) { val getArea: (Double, Double) -> Double = ::triangleArea //调用函数 val area = getArea(50.0, 40.0) print(area) //1000.0 }
每一个函数都有函数类型,即便是函数列表中没有参数,以及没有返回值的函数也有函数类型,如代码sayHello()函数,sayHello()函数的函数类型是()->Unit。
package com.work.section //该函数的返回值类型是:函数类型,即(Int, Int) -> Int fun calculate(opr: Char): (Int, Int) -> Int { //加法函数 fun add(a: Int, b: Int): Int { return a + b } //减法函数 fun sub(a: Int, b: Int): Int { return a - b } val result: (Int, Int) -> Int = when (opr) { //函数引用,采用“双冒号加函数名”形式引用,add和sub是两个局部函数,它们的函数引用表示方式是::add和::sub '+' -> ::add '-' -> ::sub //匿名函数 '*' -> { //乘法匿名函数 fun(a: Int, b: Int): Int { return (a * b) } } else -> { a, b -> (a / b) } //除法Lambda表达式 } return result } fun main(args: Array<String>) { //f0的类型是函数类型,即(Int, Int) -> Int val f0:(Int, Int) -> Int = calculate('+') println(f0(10, 5)) //调用f0变量 //如果表达式返回类型确定了,则可以省略变量后的类型声明 val f1 = calculate('+') println(f1(10, 5)) //调用f1变量 //f2的类型是函数类型,即(Int, Int) -> Int val f2 = calculate('-') println(f2(10, 5)) //f3的类型是函数类型,即(Int, Int) -> Int val f3 = calculate('*') println(f3(10, 5)) //f4的类型是函数类型,即(Int, Int) -> Int val f4 = calculate('/') println(f4(10, 5)) }
其中,calculate函数的返回类型就是(Int, Int) -> Int函数类型,说明calculate是高阶函数。
输出结果:
2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: --------函数类型输出 加、加、减、乘、除------- 2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: 15 2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: 15 2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: 5 2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: 50 2021-04-19 15:21:48.616 17243-17243/com.xw.kotlinforandroid I/System.out: 2
可以把函数作为另一个函数的返回值使用,那么这个函数属于高阶函数。
package com.work.section //定义计算长方形面积函数 //函数类型: (Double, Double) -> Double fun rectangleArea(width: Double, height: Double): Double { return width * height } //定义计算三角形面积函数 //函数类型: (Double, Double) -> Double fun triangleArea(bottom: Double, height: Double) = 0.5 * bottom * height //返回类型为函数类型,即 (Double, Double) -> Double fun getArea(type: String): (Double, Double) -> Double { var returnFunction: (Double, Double) -> Double; when (type) { "rect" -> //rect 表示长方形 returnFunction = ::rectangleArea else -> //tria 表示三角形 returnFunction = ::triangleArea } return returnFunction } fun main(args: Array<String>) { //获得计算三角形面积函数 var area: (Double, Double) -> Double = getArea("tria") println("底10 高13,计算三角形面积:${area(10.0, 15.0)}") //获得计算长方形面积函数 area = getArea("rect") println("宽10 高15,计算长方形面积:${area(10.0, 15.0)}") }
//定义计算长方形面积函数 //函数类型: (Double, Double) -> Double fun rectangleArea(width: Double, height: Double): Double { return width * height } //定义计算三角形面积函数 //函数类型: (Double, Double) -> Double fun triangleArea(bottom: Double, height: Double) = 0.5 * bottom * height //高阶函数,funcName参数是函数类型:(Double, Double) -> Double fun getAreaByFunc(funcName: (Double, Double) -> Double, a: Double, b: Double): Double { return funcName(a, b) } fun main(args: Array<String>) { //获得计算三角形面积函数 var result = getAreaByFunc(::triangleArea, 10.0, 15.0) ② println("底10 高15,计算三角形面积:$result") ③ //获得计算长方形面积函数 result = getAreaByFunc(::rectangleArea, 10.0, 15.0) ④ println("宽10 高15,计算长方形面积:$result") ⑤ }
运行结果:
底10 高15,三角形面积:75.0 宽10 高15,计算长方形面积:150.0
{ 参数列表 -> Lambda体 }其中, Lambda 表达式的参数列表与函数的参数列表形式类似,但是 Lambda 表达式参数列表前后没有小括号。箭头符号将参数列表与Lambda 体分隔开, Lambda 表达式不需要声明返回类型。 Lambda 表达式可以有返回值,如果没有 return 语句 Lambda 体的最后一个表达式就是Lambda 表达式的返回值,如果有 return 语句返回值是 return 语句后面的表达式。 提示: Lambda 表达式与函数、匿名函数一样都有函数类型,但从 Lambda 表达式的定义中只能看到参数类型,看不到返回类型声明,那是因为返回类型可以通过上下文推导出来。
private fun calculate(opr: Char): (Int, Int) -> Int { return when (opr) { //lambda表达式 '+' -> { a: Int, b: Int -> a + b } '-' -> { a: Int, b: Int -> a - b } '*' -> { a: Int, b: Int -> a * b } else -> { a: Int, b: Int -> a / b } } } fun main(args: Array<String>) { val f1 = calculate('+') println(f1(10, 5)) //调用f1变量 val f2 = calculate('-') println(f2(10, 5)) val f3 = calculate('*') println(f3(10, 5)) val f4 = calculate('/') println(f4(10, 5)) }
Lambda表达式也是函数类型,可以声明变量,也可以作为其他函数的参数或者返回值使用。
{ a: Int, b: Int -> a + b }
Kotlin能推导出参数a和b是Int类型,当然返回值也是Int类型。简化形式如下:
{ a, b -> a + b }
② 使用尾随Lambda表达式
Lambda表达式可以作为函数的参数传递,如果Lambda表达式很长,就会影响程序的可读性。如果一个函数的最后一个参数是Lambda表达式,那么这个Lambda表达式可以放在函数括号之后(注意这里所说的lambda表达式是包括花括号"{}"的)。示例代码如下:
fun calculatePrint1(funN: (Int, Int) -> Int) { //参数是函数类型 //使用funN参数 println("${funN(10, 5)}") } //打印计算结果函数 最后一个参数是函数类型:(Int, Int) -> Int fun calculatePrint(n1: Int, n2: Int, opr: Char, funN: (Int, Int) -> Int) { println("${n1} ${opr} ${n2} = ${funN(n1, n2)}") } fun main(args: Array<String>) { calculatePrint(10, 5, '+', { a, b -> a + b })//标准形式 calculatePrint(10, 5, '-') { a, b -> a - b }//尾随Lambda表达式形式 //最后一个参数是lambda表达式:{ a, b -> a + b } calculatePrint1({ a, b -> a + b })//标准形式 calculatePrint1() { a, b -> a + b }//尾随Lambda表达式形式 calculatePrint1 { a, b -> a + b }//尾随Lambda表达式,如果小括号里没有参数可省略小括号 }
注意:由于calculatePrint1函数只有一个lambda表达式作为参数,它采用了尾随Lambda表达式形式,这样一来它的小括号中就没有参数了,这种情况下可以省略小括号。
③ 省略参数声明
如果Lambda表达式的参数只有一个,并且能够根据上下文环境推导出它的数据类型,那么这个参数声明可以省略,在Lambda体中使用隐式参数it替代Lambda表达式的参数。
fun revreseAndPrint(str: String, funN: (String) -> String) { val result = funN(str) println(result) } fun main(args: Array<String>) { revreseAndPrint("hello", { s -> s.reversed() })//标准形式 revreseAndPrint("hello", { it.reversed() })//省略参数,使用隐式参数it //由于result1被未指定数据类型,编译器不能推导出来Lambda表达式的参数类型,所以不能使用it。 val result1 = { a: Int -> println(a) }//不能省略参数声明 //由于result2被指定了数据类型(Int)->Unit,编译器能推导出 Lambda表达式的参数类型,所以可以使用it。 val result2:(Int)->Unit = { println(it) }//可以省略参数声明 result2(30) //输出结果是30 }
注意 Lambda体中it隐式变量是由Kotlin编译器生成的,它的使用有两个前提:一是Lambda表达式只有一个参数,二是根据上下文能够推导出参数类型。
④lambda表达式与return语句
Lambda 表达式体中也可以使用 return 语句,它会使程序跳出 Lambda表达式体。 提示 forEach 是集合、数组或区间的函数,如果它后面是一个 Lambda 表达式,集合、数组或区间对象调用forEach 函数时,会将它们的每一个元素传递给 Lambda 表达式并执行。 示例代码如下://累加求和函数 fun sum(vararg num: Int): Int { var total = 0 //forEach后面跟的是一个lambda表达式 num.forEach { //if (it == 10) return -1 //返回到最近的函数,即sum函数 //@forEach是隐式声明标签,标签名是Lambda表达式所在函数名(forEach)。 if (it == 10) return@forEach//返回Lambda表达式函数 total += it } return total } fun main(args: Array<String>) { val n = sum(1, 2, 10, 3) println(n) //6 //label@是Lambda表达式显示声明标签 val add = label@ { val a = 1 val b = 2 return@label 6666 a + b } //调用Lambda表达式add println(add()) //6666 }
上述代码num.forEach是使用了forEach函数,它后面的Lambda表达式,如果使用代码 if (it == 10) return -1语句,则会返回最近的函数,即sum函数,不是返回 Lambda表达式forEach。为了返回Lambda表达式则需要在return语句后面加上标签,即“if (it == 10) return@forEach”,@forEach是隐式声明标签,标签名是Lambda表达式所在函数名(forEach)。也可以为Lambda表达式声明显示标签,代码label@是Lambda表达式显示声明标签,代码“ return@label 10 ”是使用显示标签。
2021-04-19 18:04:19.279 28687-28687/com.xw.kotlinforandroid I/System.out: 6 2021-04-19 18:04:19.279 28687-28687/com.xw.kotlinforandroid I/System.out: 6666