1、定义和调用函数及函数返回值Unit
fun 函数名 (形参列表) : 返回值类型{
函数体
}
可以省略返回值类型
如果返回值类型为:Unit则为无返回值,等同于java的void
2、递归函数
fun main() {
var n=5
var resualt= jiechen(n)
println(resualt)
}
fun jiechen(n:Int):Int{
if (n==1){
return 1
}else{
return n* jiechen(n-1)
}
}
打印
120
3、单表达式函数
函数体只有一行语句的时候,省略掉大括号的写法
fun main() {
var a=5.25
var b=3.4
println(area(a,b))
}
fun area(x:Double,y:Double):Double=x*y;
打印:
17.849999999999998
4、形参默认值
形参名:形参类型=默认值
fun main() {
var a=5.25
var b=3.4
println(area(a,b))
}
fun area(x:Double,y:Double,pi:Double=3.1415):Double=x*y*pi;
打印:
56.07577499999999
fun main() {
var a=5.25
var b=3.4
println(area(a,b,5.5))//这里覆盖了pi的默认值
}
fun area(x:Double,y:Double,pi:Double=3.1415):Double=x*y*pi;
打印:
98.17499999999998
fun main() {
var a=5.25
var b=3.4
println(area(a,5.5))//按顺序5.5赋值给了y
}
fun area(x:Double,y:Double,pi:Double=3.1415):Double=x*y*pi;
打印
90.7108125
5、尾递归函数
当函数将调用自身作为它执行的最后一行大麦,且递归调用后没有更多代码时,可以使用尾递归语法,当然需要使用tailrec修饰符
以下函数形式:
fun main() {
var n=5
var resualt= jiechen(n)
println(resualt)
}
fun jiechen(n:Int):Int{
if (n==1){
return 1
}else{
return n* jiechen(n-1)
}
}
都可以改成为
fun main() {
var n=5
var resualt= jiechen(n)
println(resualt)
}
tailrec fun jiechen(n:Int,total:Int=1):Int=if (n==1) total else jiechen(n-1,total*n)
以上两段代码都打印120
6、个数可变的形参
需要加vararg修饰符,实际上就是把可变形参当作一个数组来处理
fun main() {
var n=5
iterator(n,"java","swift","android")
}
fun iterator(a:Int,vararg books:String){
for (b in books){
println(b+a)
}
}
打印
7、函数重载
同名函数,形参列表或返回值不同即可以重载
fun main() {
var n=5
overridefun()
overridefun("zhangsan")
overridefun("zhangsan",10)
}
fun overridefun(){
println("无参数的重载")
}
fun overridefun(str:String){
println("带一个参数${str}的重载")
}
fun overridefun(name:String, age:Int){
println("带两个参数的重载,名字:${name},年龄:${age}")
}
打印:
无参数的重载
带一个参数zhangsan的重载
带两个参数的重载,名字:zhangsan,年龄:10
8、局部函数
就是函数内部的函数
fun main() {
println(innerFun(2,5))
}
fun innerFun(type: Int, width: Int):Int {
var resualt=0
//计算平方
fun squre(width: Int): Int {
return width * width
}
//计算立方
fun cube(width: Int): Int {
return width * width * width
}
when (type) {
1 -> return squre(width)
2 -> return cube(width)
else-> return 0
}
}
打印
125
9、高阶函数–函数类型
函数类型指函数的参数类型,->符号,返回类型,这三者形成,通过对函数应用,可以让我们的函数使用更加灵活
fun main() {
//定义一个函数类型为:(Int,Int)->Int
var myfun:(Int,Int)->Int
myfun=::caculateFun
println(myfun(1,5))
}
fun caculateFun(type: Int, width: Int):Int {
var resualt=0
//计算平方
fun squre(width: Int): Int {
return width * width
}
//计算立方
fun cube(width: Int): Int {
return width * width * width
}
when (type) {
1 -> return squre(width)
2 -> return cube(width)
else-> return 0
}
}
打印:
25
10、使用函数类型作为形参类型
当函数的大部分逻辑都能确定,但某些处理逻辑暂时无法确定,意味着某些程序代码需要动态改变,这时候可以在形参中定义函数类型的参数,
fun main() {
//定义一个整形数组
var data= arrayOf(3,4,5,7,9,45)
//原数据
println("data的原数据为:"+data.contentToString())
//平方计算
println("每个数组元素平方"+map(data, ::squre).contentToString())//这里只需要传入参数名即可,不需要给定参数,因为在应用的函数里面已经给定参数了
//立方计算
println("每个数组元素立方"+map(data, ::cube).contentToString())//这里只需要传入参数名即可,不需要给定参数,因为在应用的函数里面已经给定参数了
}
fun map(data:Array<Int>,fn:(Int)->Int):Array<Int>{
var resualt=Array<Int>(data.size,{0})
for (i in data.indices){
resualt[i]=fn(data[i])
}
return resualt
}
//计算平方
fun squre(width: Int): Int {
return width * width
}
//计算立方
fun cube(width: Int): Int {
return width * width * width
}
打印:
data的原数据为:[3, 4, 5, 7, 9, 45]
每个数组元素平方[9, 16, 25, 49, 81, 2025]
每个数组元素立方[27, 64, 125, 343, 729, 91125]
11、使用函数类型作为返回值类型
顾名思义
fun main() {
var mathFun= getMathFun(1)
println(mathFun(5))
mathFun= getMathFun(2)
println(mathFun(5))
}
fun getMathFun(type: Int):(Int)->Int {
var resualt=0
//计算平方
fun squre(width: Int): Int {
return width * width
}
//计算立方
fun cube(width: Int): Int {
return width * width * width
}
when (type) {
1 -> return ::squre
else -> return ::cube
}
}
25
125
12、局部函数与Lambda表达式
lambda和函数的区别
- lambda表达式总是被大括号包裹
- 定义lambda表达式不需要fun关键字,无须指定函数名
- 形参列表(如果有的话)在->之前申明,参数类型可以省略
- 函数体(lambda表达式执行体)放在->之后
- 函数的最后一个表达式自动被作为lambda表达式的返回值,无需使用return关键字
fun main() {
var mathFun= getMathFun(1)
println(mathFun(5))
mathFun= getMathFun(2)
println(mathFun(5))
}
fun getMathFun(type: Int):(Int)->Int {
when (type) {
1 -> return { width:Int->Int
width*width
}
else -> return { width:Int->Int
width*width*width
}
}
}
打印
25
125
13、Lambda表达式的脱离
作为函数参数传入的lambad表达式可以脱离函数独立使用。
import kotlin.collections.ArrayList
//定义一个List类型变量,泛型类型为函数类型
var lambdaList=ArrayList<(Int)->Int>()
//定义一个函数,该函数的形参为函数
fun collectFun(fn:(Int)->Int){
lambdaList.add(fn)
}
fun main() {
//调用函数两次,将会向lambdaList中添加元素,每个元素都是lambda表达式
collectFun ({it*it})
collectFun ({it*it*it})
println(lambdaList.size)
//依次调用lambdaList集合的元素(每个元素都是lambda表达式)
for (i in lambdaList.indices){
//调用每一个元素(函数),参数在序号的基础上+10
println(lambdaList[i](i+10))
}
}
打印:
2
100
1331
14、Lambda表达式
lambda表达式标准语法
{
(形参列表)->
//零到多条可执行语句
}
15、调用Lambda表达式
直接将lambda表达式赋值给变量或者直接调用lambda表达式
fun main() {
var square={n:Int->
n*n
}
println(square(5))
var result={base:Int,exponent:Int->
var result=1
for (i in 1..exponent){
result*=base
}
result//lambda的最后一条语句为返回语句
}(4,5)//这里直接定义玩就立刻使用
println(result)
}
打印:
25
1024
16、利用上下文推断类型
如果上下文可以推断出形参的类型,则可以省略lambda表达式的形参类型
fun main() {
//由于返回值类型可以确定,所以可以推断出形参类型
var sqare:(Int)->Int={n-> n*n}
print(sqare(5))
}
打印
25
17、省略形参名
如果只有一个形参,则可以省略形参名,同时->符号也可以一通省略,lambda表达式使用 it 来代表形参
fun main() {
//由于返回值类型可以确定,所以可以推断出形参类型
var sqare:(Int)->Int={it*it}
print(sqare(6))
}
打印
36
18、调用Lambda表达式的约定(尾随闭包)
如果函数的最后一个参数是函数类型,而且你打算传入一个lambda表达式作为相应的参数,那么就允许在圆括号之外指定lambda表达式
fun main() {
var list= listOf<String>("java","kotlin","go")
//最后一个参数是lambda表达式,可将表达式写在圆括号外面
var rt=list.dropWhile (){ it.length>3 }
println(rt)
var map= mutableMapOf("疯狂安卓讲义" to 56)
list.associateTo (map){"疯狂${it}讲义" to it.length }
println(map)
}
[go]
{疯狂安卓讲义=56, 疯狂java讲义=4, 疯狂kotlin讲义=6, 疯狂go讲义=2}
19、个数可变的参数和lambda参数
当被调用的函数既包含个数可变的形参,也包含函数类型的形参,那么就应该将函数类型的的形参放在最后,此外lambda也无须使用命名参数
fun <T>test(vararg names:String,transform:(String)->T):List<T>{
var mutableList:MutableList<T> = mutableListOf()
for (name in names){
mutableList.add(transform(name))//使用了参数类型
}
return mutableList.toList()
}
fun main() {
//将lambda表达式放在圆括号后面,无需使用命名参数
var list1= test("java","kotlin","go"){it.length}
println(list1)
var list2= test("java","kotlin","go"){"疯狂${it}讲义"}
println(list2)
}
打印
[4, 6, 2]
[疯狂java讲义, 疯狂kotlin讲义, 疯狂go讲义]
20、匿名函数的用法
同java的匿名函数
如果匿名函数的形参类型可以推断出来,匿名函数的形参类型也可以不写
定义的匿名函数的函数体如果是单表达式,可以省略声明函数的返回值
fun main() {
var test=fun(x:Int,y:Int):Int{
return x+y
}
println(test(3,4))
//省略形参类型
var filteredList= listOf(3,4,5,6,7,9,34,56,32).filter (
//使用匿名函数作为filter()方法的参数
fun (el):Boolean{
return Math.abs(el)>20
})
println(filteredList)
//定义的函数如果是单表达式,省略形参类型及返回值类型
var wawa=fun(x:Int,y:Int)=x+y
println(wawa(3,5))
var rt=listOf(3,4,5,6,7,9,34,56,32).filter (
//使用匿名函数作为filter()方法的参数
fun (el)=Math.abs(el)>20
)
println(rt)
}
打印:
7
[34, 56, 32]
8
[34, 56, 32]
21、匿名函数和Lambda表达式的return
匿名函数的return用于返回函数本身,而lambda表达式的return用于返回它所在的函数,而不是返回lambda表达式
fun main() {
var list= listOf<Int>(3,4,5,678,23)
//使用匿名函数返回函数本身
list.forEach(fun(n){
println("元素依次为:${n}")
return //返回匿名函数本身
})
println("------")
//使用匿名的lambda表达式返回lambda表达式所在的函数,所以无法正确依次输出,输出第一个以后就return了
list.forEach({ n ->
println("元素依次为:${n}")
return//返回所在的函数,main函数
})
}
打印
元素依次为:3
元素依次为:4
元素依次为:5
元素依次为:678
元素依次为:23
------
元素依次为:3
22、捕获上下文中的变量和常量
lambda表达式或是匿名函数(以及局部函数、对象表达式)可以访问或修改器所在上下文(俗称闭包)中的变量和常量,这个过程称之为捕获。即使定义这些变量和常量的作用域已经不存在了,lambda表达式或匿名函数也依然可以访问或修改他们。
//定义一个函数,该函数的返回值类型()->List<String>
fun makeList(ele:String):()->List<String>{
//创建一个空的list集合
var list:MutableList<String> = mutableListOf()
fun addElement():List<String>{
//向list集合中添加一个元素
list.add(ele)//这里的ele是从外层函数参数中捕获的
return list
}
return ::addElement//返回一个函数
}
返回的事是list的副本,而非list本身
23、内联函数概述
高阶函数调用过程中式有调用函数去复制+粘贴被调用函数的。这种工作通常通过内联函数来实现
在复制+粘贴的代码量不是太高的情况下,可以使用,如果复制粘贴量比较大,则不建议使用内联函数
24、内联函数的使用
内联函数使用inline关键字修饰
fun main() {
var arr= arrayOf(29,35,67,8,9)
var mappedResult= map(arr,{it+3})
println(mappedResult.contentToString())
}
inline fun map(data:Array<Int>,fn:(Int)->Int):Array<Int>{
var result=Array<Int>(data.size,{0})
for (i in data.indices){
result[i]=fn(data[i])
}
return result
}
打印
[32, 38, 70, 11, 12]
25、部分禁止内联
使用noinline用于显示阻止某一个或某几个形参内联化
fun main() {
test({it*it},{"《疯狂讲${it}义》"})
}
inline fun test(fn1:(Int)->Int,noinline fn2:(String)->String){
println(fn1(20))
println(fn2("kotlin"))
}
打印
400
《疯狂讲kotlin义》