Kotlin笔记高阶函数(七)

Kotlin笔记高阶函数(七)

Kotlin笔记数据类型(一)
Kotlin笔记字符串(二)
Kotlin笔记运算符(三)
Kotlin笔记函数(四)
Kotlin笔记面向对象(五)
Kotlin笔记继承、抽象类、接口(六)



一、高阶函数

一个函数可以作为另一个函数的参数,或者返回值,那么这个函数就是“高阶函数”

2、函数类型

Kotlin中每一个函数都有一个类型,称为“函数类型”,函数类型作为一种数据类型与数
据类型在使用场景没有区别

//定义计算长方形面积函数
//函数类型(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 ②
fun sayHello() {
    
     //函数类型()->Unit ③
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
}

3、函数字面量

函数类型可以声明的变量,那么函数类型变量能够接收什么的数据呢?即函数字面量如何
表示的问题,函数字面量可以有三种表示:

  • 函数引用。引用到一个已经定义好的,有名字的函数。它可以作为函数字面量。
  • 匿名函数。没有名字的函数,即匿名函数,它也可以作为函数字面量。
  • Lambda表达式。Lambda表达式是一种匿名函数,可以作为函数字面量。
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 ②
'*' -> {
    
    
//乘法匿名函数
fun(a: Int, b: Int): Int {
    
     
return (a * b)
}
}
else -> {
    
     a, b -> (a / b) } //除法Lambda表达式 ④
}
return result
}
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))
}

4、函数作为返回值

fun main(args: Array<String>) {
    
    

    var funName=getFunWithType(2)

    println(funName(1,3))
}
fun getFunWithType(type:Int):(Int,Int)->Int{
    
    
    var functionType:(Int,Int)->Int
    when(type){
    
    
        1-> functionType=fun (a:Int,b:Int):Int=a+b
        else -> functionType={
    
    a,b->a-b}
    }

    return functionType
}

5、函数作为参数

fun main(args: Array<String>) {
    
    
    var funName=getFunWithType(2)
    println(operterFun(funName,4,5))
}
fun operterFun(funName:(Int,Int)->Int,a: Int,b: Int):Int{
    
    
    return funName(a,b)
}
fun getFunWithType(type:Int):(Int,Int)->Int{
    
    
    var functionType:(Int,Int)->Int
    when(type){
    
    
        1-> functionType=fun (a:Int,b:Int):Int=a+b
        else -> functionType={
    
    a,b->a-b}
    }

    return functionType
}

二、Lambda表达式

1、Lambda表达式标准语法

{ 参数列表 -> Lambda体 }

Lambda表达式的参数列表与函数的参数列表形式类似,但是Lambda表达式参数列
表前后没有小括号。箭头符号将参数列表与Lambda体分隔开,Lambda表达式不需要声明
返回类型。Lambda表达式可以有返回值,如果没有return语句Lambda体的最后一个表
达式就是Lambda表达式的返回值,如果有return语句返回值是return语句后面的表达
式。

fun main(args: Array<String>) {
    
    

    var funLa={
    
    a:Int,b:Int-> a+b}

    println(funLa(2,4))

}

2、Lambda表达式 简化写法

{a:Int,b:Int-> a+b} 可以简化成
{ a, b -> a + b }

尾随Lambda 如果一个函数的最后一个参数是Lambda表达式,那么这个Lambda表达
式可以放在函数括号之后。

fun main(args: Array<String>) {
    
    

    //正常调用
//    operterFun(2,3,{a,b->a+b})
    
    //尾随写法
    operterFun(2,3){
    
    a,b->
        a+b
    }
}

fun operterFun(a: Int,b: Int,funName:(Int,Int)->Int):Int{
    
    
    return funName(a,b)
}

如果Lambda表达式的参数只有一个,并且能够根据上下文环境推导出它的数据类
型,那么这个参数声明可以省略,在Lambda体中使用隐式参数it替代Lambda表达
式的参数

fun main(args: Array<String>) {
    
    
    
    operterLa("zyb"){
    
     println(it)}

}


fun operterLa(name:String,funName: (String)->Unit){
    
    
    funName(name)
}

3、Lambda表达式与return语句

Lambda表达式体中也可以使用return语句,它会使程序跳出Lambda表达式体

fun main(args: Array<String>) {
    
    

    println(sum(1,2,3,10,3)) //9
    val add = label@ {
    
    
        val a = 1
        val b = 2
        return@label 10
        a + b
    }
//调用Lambda表达式add
    println(add()) //10
}


//累加求和函数
fun sum(vararg num: Int): Int {
    
    
    var total = 0
    num.forEach {
    
    
//        if (it == 10) return -1 //返回最近的函数 ②
        if (it == 10) return@forEach//返回Lambda表达式函数 ③
        total += it
    }
    return total
}

三、闭包与捕获变量

闭包(closure)是一种特殊的函数,它可以访问函数体之外的变量,这个变量和函数一
同存在,即使已经离开了它的原始作用域也不例外。这种特殊函数一般是局部函数、匿名
函数或Lambda表达式

fun makeArray(): (Int) -> Int {
    
     ①
var ary = 0//局部函数捕获变量
fun add(element: Int): Int {
    
     ③
ary += element ④
return ary ⑤
}
return ::add ⑥
}
fun main(args: Array<String>) {
    
    
val f1 = makeArray()println("---f1---")
println(f1(10))//累加ary变量,输出结果是10
println(f1(20))//累加ary变量,输出结果是30
}

四、内联函数

在高阶函数中参数如果是函数类型,则可以接收Lambda表达式,而Lambda表达式在编译
时被编译称为一个匿名类,每次调用函数时都会创建一个对象,如果这种被函数反复调用
则创建很多对象,会带来运行时额外开销。为了解决次问题,在Kotlin中可以将这种函数
声明为内联函数。
提示 内联函数在编译时不会生成函数调用代码,而是用函数体中实际代码替换每次
调用函数

1、内联函数定义

使用关键字 inline

inline fun calculatePrint(funN: (Int, Int) -> Int) {
    
    println("${funN(10, 5)}")
}
fun main(args: Array<String>) {
    
    
calculatePrint {
    
     a, b -> a + b } ②
calculatePrint {
    
     a, b -> a - b }}

2、使用let函数

在Kotlin中一个函数参数被声明为非空类型时,也可以接收可空类型的参数,但是如果实
际参数如果真的为空,可能会导致比较严重的问题。因此需要在参数传递之前判断可空参
数是否为非空

fun main(args: Array<String>) {
    
    


sayNameLength(null)
}


fun sayNameLength(name:String?){
    
    
//    if (name!=null){
    
    
//        println(name.length)
//    }
    name?.let {
    
    println(it.length) }
}

2、使用with和apply函数

有时候需要对一个对象设置多个属性,或调用多个函数时,可以使用with或apply函数。
与let函数类似Kotlin中所有对象都可以使用这两个函数

with 返回表达式的最后一句,apply 返回的是一个对象

fun main(args: Array<String>) {
    
    


//sayNameLength(null)


    var name=StringBuilder(0)

    var stringBuilder2=name.apply{
    
    
        append("hello")
        append("  ")
        append("world")

    }

    var stringBuilder3= with(name){
    
    
        this.append("\n")
        this.append("My name is ")
        this.append("zyb")
        "我是with"
    }

    println(name)
    println(stringBuilder2)
    println(stringBuilder3)

## hello  world
## My name is zyb
## hello  world
## My name is zyb
## 我是with
}

猜你喜欢

转载自blog.csdn.net/baidu_31956557/article/details/109290124