注意事项:
1:只要在一个函数的函数体实现中再次调用了函数本身,就是递归函数。递归函数一定要向已知方向进行
2.函数只返回单个表达式,则可以用等号=即可 fun area(x:Double):Double =x,而对于单表达式函数而言,编译器可以自动推断函数的返回值类型,因此也可以改为fun area(x:Double)=x
3.Kotlin允许调用函数时通过名字来传入参数值,因此,Kotlin函数的参数名应该具有更好的语义
4.在某些情况下,程序需要在定义函数时为一个或多个形参指定默认值—这样调用函数时就可以省略该形参,而直接调用该形参的默认值。格式:形参名:形参类型 = 默认值
fun sayHi(name: String ="luotianyou"){}
5.如果在定义函数时,在形参的类型前添加vararg修饰,则表明该参数可以接受多个参数值,多个参数值被当成数组传入
6.Kotlin允许个数可变的形参可以处于形参列表的任意位置(不要求时形参列表的最后一个参数),但Kotlin要求一个函数最多只能带一个个数可变的形参
7.Kotlin函数中的参数不能定义是val,还是var,会默认指定为是val, 不能去修改参数值
8,Kotlin的函数重载也只能通过形参列表进行区分,形参个数不同,形参类型不同都可以算函数重载,但是仅有形参名不同、返回值不同或修饰符不同,则不能算函数重载
9,大部分时候不推荐重载形参个数可变的函数,这样做没有意义且容易导致错误
10.Kotlin支持在函数体内部定义函数,这种函数被称为局部函数,局部函数在默认情况下对外部是隐藏的,其封闭函数也可以返回局部函数,以便程序在其他作用域中使用局部函数
11.Kotlin不是纯粹的面向对象语言,Kotlin的函数也是一等公民,因此函数本身也具有自己的类型,函数类型就像数据类型一样,既可用于定义变量,也可用作函数的形参类型,还可作为函数的返回值类型
12.Kotlin的每个函数都有特定的数据类型,函数类型由函数的形式参数、->和返回值类型组成
13.Kotlin可以使用函数类型可以作为形参类型,也可以使用函数类型作为返回值:参考如下程序
fun map(data:Array,fn:(Int)->Int):Array{
var result =Array(data.size,{0})
for(i in data.indices){
result[i]=fn(data[i])
}
return result
}
fun square(n:Int):Int{
return n*n
}
fun cube(n:Int):Int{
return n*n*n
}
fun main(args:Array){
var data = arrayOf(1,3,5,7,9)
val size=map(data,::square)
id_text.text=size[0].toString()}
fun map():(Int)->Int{
fun cube(n:Int):Int{
return n*n*n
}
return ::cube
}
fun main(args:Array){
val size=map()
id_text.text=size(10).toString()}
14.Lambda表达式对于不需要复用的局部函数,可以简化局部函数的写法,因此,Lambda表达式修改上述程序,可以修改为
fun map():(Int)->Int{
return {n:Int->n*n}
}
fun main(args:Array){
val size =map()
println(size(10).toString))
}
Lambda表达式总是被大括号扩着
定义lambda表达式无需fun关键字和函数名
形参列表在->之前声明,参数类型可以省略
函数体放在->之后
函数的最后一个表达式自动被作为lambda表达式的返回值
15.Lambda表达式的脱离
var lambadList = java.util.ArrayList<(Int)->Int>()
fun test(fn:(Int)->Int){
lambadList.add(fun)}
fun main(args:Array){
test({it*it})
test({it*it*it})
for(i in lambadList.indices){
println(lambadList[i](i+10))
}
}
16.调用lambda表达式
val square={n:Int -> n*n}
println(square(5))
17.利用上下文推断类型,上文
var square:(Int)->Int={n->n*n}
18.lambda表达式不仅可以省略形参雷士,而且如果只有一个形参,那么K允许省略lambda表达式的形参名,如果lambda表达式省略的形参名,那么此时->也不需要了,如下
var square:(Int)->Int={it*it}
19.如果函数的最后一个参数时函数类型,而且打算传入一个Lambda表达式作为相应的参数,那么久允许在圆括号之外指定lambda表达式,因此建议将函数类型的形参放在参数列表的最后
20.由于lambda表达式不能指定返回值类型,此时就需要使用匿名函数替代lambda表达式来显示指定返回值类型,如果系统可以推断出匿名函数的形参类型,那么允许省略形参类型
val max=fun(vararg x:Int):Int{
return x[0]
}
21.匿名函数的本质仍然是函数,因此匿名函数的return则用户返回函数本身,而lambda表达式的return用于返回它所在的函数,而不是返回lambda表达式,下述代码之所以可以在lambda表达式中直接使用return,是因为forEach方法使用了inline修饰,因此它相当于一个内联函数
var list=listOf(3,5,8,9,7,1)
list.forEach(fun(n){
println($n)//遍历list集合,打印所有数据
return
}
list.forEach({n->
println($n)//只打印一个数组元素
return
}
22.***lambda表达式或匿名函数可以访问或修改其所在上下文中的变量和常量,会为这项常量和变量创建一个副本
23.内联函数,先简单说一下高阶函数(为函数传入函数或lambda表达式作为参数)的调用过程。
为被调用的表达式或函数创建一个对象
为被调用的表达式或函数所捕获的变量创建一个副本
在跳转到被调用的表达式或函数所在的地址之前,要先保护现场并记录执行地址;从被调用的表达式或函数地址返回时,要先恢复现场,并按原来保存的地址继续执行,也就是常说的压栈和出栈
为了避免产生函数调用的过程,Kotlin可以使用inline关键字来讲被调用的表达式或函数“嵌入”原来的执行流中,内联函数是以目标代码的增加为代价来节省事件开销的,因此只适合于lambda表达式或函数只包含非常简单的执行代码
fun main(args:Array){
var x=map { it*it }
}
inline fun map(fn:(Int)->Int):Int{
var x=fn(3)
return x
}