Kotlin学历之函数与Lambda表达式

简述

类和对象的内容基本学完了,接下来将深入研究下Kotlin中的函数,与java相比,Kolin中的函数相对灵活很多,像命名参数语法,局部函数,高阶函数,尾递归函数等都会带来新的函数特性,用起来也是方便的很。本文主要研究函数和lambda表达式的常见语法及规则,后期将对高阶函数展开学习,下面开始基础讲解。

函数声明

fun  函数名(参数名:参数类型,参数名:参数类型):返回值类型{ 
return 返回值
}

这里的“:”很有意思,简单比对一下就忽然明白了为啥这么写了,看下面

数名:参数类型
函数名():返回值类型
对象名:父类、接口
//现在明白了吗,格式统一,“:”左边就相当于类的实现:对象,右边就是它的类。

函数调用方式

demo(1)
Sample.demo(1)
// 调用方式和java一样 但有一种调用方式不同 叫中辍调用

中辍表示法有如下特点:

是成员函数或扩展函数
**只有一个参数
**用infix关键字标注

例如:

infix fun Int.shl(x:Int) :Int{……}
//调用方式
1 shl 2  // 可以这么调用
1.shl(2)  //正常写法

参数声明规则

格式是 name:_type,_参数用逗号隔开,每个参数必须有显式类型

默认参数

函数参数可以有默认值,当省略相应的参数时使用默认值。与其他语言相比,这可以减少重载数量

例1:

fun read(b :Array, off: Int= 0, len :Int = b.size()) {
…… // off 默认值0,len 的默认是是b 集合大小
}

例2:

//当覆盖一个带有默认参数值的方法时,必须省略默认参数值

override fun read(b :Array, off: Int, len :Int)

命名参数语法

这个目前看来是最重要的一个点,与java相比比较特殊,可以省去很对重载

例如在java中你定义这么几个函数

public void add(int a)
public void add(int a, String b)
public void add(int a, String b, boolean c)
public void add(int a, boolean c)

而在kotlin中只需要这样一行

fun add(a :Int , b :String ="bb",c :Boolean =false)

在使用过程中就可以这样使用

add (1)
add (1, "c")
add (1, "c",true )
//更可以这样 利用参数名直接用“=”号赋值
add ( a= 3, c = true)

Unit函数

unit 就相当于java中的void 一个意思,自己脑补吧不举例了,哈哈

单表达式函数

在kotlin中的函数是可以直接 用“=”号 代替大括号的函数体 

例如:

fun double(x:Int):Int= x * 2 
// 返回值类型也是可以省去
fun double(x:Int)= x * 2 // 这里是一个参数 可以推断出类型 所以可以省去,如果多个参数时,推断不出来就不可以省去了

可变数量参数


在java中 会用到“...” 来表示可变参数,在kotlin中则要使用Varargs 关键字修饰

例如:

fun add( vararg  a : Int){

}
//这样就可以这么调用了

add ( 1,2,4,5,6,3,1)

可变参数还有个“*”操作符直接将一个同等类型的参数传递进来 

例如:

var arraya = arrayOf(1,2,3,4,5,6)
var arrayb= add( 2,6,7,89, *arraya) //这样就传进来了a的参数

成员函数

成员函数是在类或对象内部定义的函数,与java 一样,没什么特殊的

局部函数


局部函数就像java中的局部变量一样,在函数体里面的函数就是局部函数

例如:其实说白了就相当于在java 函数内部调用外部函数,只是说函数定义在 函数内部。

fun  add ( a : Int ){
fun add( b : String , c : Int){

      }
add( "bbb", a)
}

泛型函数

函数可以有泛型参数,通过在函数名前使用尖括号指定。与java基本相同

fun add( a : T) :T{
return a*2
}

尾递归函数

Kotlin 支持一种称为尾递归的函数式编程风格。 这允许一些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险。 当一个函数用tailrec修饰符标记并满足所需的形式时,编译器会优化该递归,留下一个快速而高效的基于循环的版本。

tailrec fun findFixPoint(x:Double= 1.0) :Double = 
if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

使用尾递归的时候请注意:要符合tailrec修饰符的条件的话,函数必须将其自身调用作为它执行的最后一个操作。在递归调用后有更多代码时,不能使用尾递归,并且不能用在 try/catch/finally 块中。目前尾部递归只在 JVM 后端中支持。

lambda表达式

lambda表达式与高阶函数应用很密切,经常会遇到,在java中也支持lambda表达式,不过目前好像没多少人用,但真正用起来,的确也是提高代码的编写效率,而且不失可读性。

例如:

val sum = { x :Int , y :Int -> x + y }

lambda 表达式总是被大括号括着, 完整语法形式的参数声明放在括号内,并有可选的类型标注, 函数体跟在一个->符号之后。如果推断出的该 lambda 的返回类型不是Unit,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。

it 关键字应用:一个 lambda 表达式只有一个参数,如果 Kotlin 可以自己计算出签名,它允许我们不声明唯一的参数,并且将隐含地为我们声明其名称为it:
val boo { it >0} 
默认: boo 是个函数,参数是 Int 类型

限定返回值:我们可以使用限定的返回语法从 lambda 显式返回一个值。否则,将隐式返回最后一个表达式的值。而且请注意,如果一个函数接受另一个函数作为最后一个参数,lambda 表达式参数可以在圆括号参数列表之外传递。 参见callSuffix的语法。

限定语法使用 @ 符号

ints.filter {
val shouldFilter= it >0 
return@filter  shouldFilter
}

总结:

除了这些当然还有内联函数、高阶函数等内容相对复杂,将放到下面的章节中学习。