【Kotlin】函数

函数表达式

函数体只有一行代码时,可以省略{},省略return ,用=连接,return不用写

fun add(x:Int,y:Int) = x+y

fun say() = println("hello")

默认参数

定义函数参数时,可以给参数定义默认值
相当于java中的方法重载

fun hello(name: String = "张三") {
    
}

具名参数

函数被调用时,可以带上参数名称
可以指定参数的赋值顺序
需要把参数名称带上

fun say(name: String, age: Int) {

}

say(age = 1, name = "哈哈")

可变参数(vararg)

fun varargs(vararg i:Int){
    for (k in i){
        println(k)
    }
}

参数列表中只能有一个vararg参数,如果该参数不是在最后一个参数位置,需要使用具名参数进行传递。
传递参数时,可以一个一个传递,如果是已有的数组进行传递时,可以使用操作符*

    varargs(1,2,3)
    //传递数组
    val arr = intArrayOf(4,5,6)
    varargs(*arr)

中缀函数

标有infix关键字的函数可以使用中缀表达法调用。
中缀表达式的函数必须满足:

  • 它们必须是成员函数扩展函数
  • 函数只能有一个参数
  • 函数参数不能是可变参数且不能有默认值
//扩展函数
infix fun Int.add(i: Int): Int {
    return this + i
}

val num = 100 add 2

//成员函数
class Infix{
    infix fun say(name:String){
        
    }
}
//调用
this say "hello"//正确
say("hello")//正确
//say ""//错误

中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符

val i = 90 add 10 * 2
val i2 = 90 add (10 * 2)
//这两种方式是等价的,中缀函数调用的优先级低

另一方面,中缀函数调用的优先级高于布尔操作符 && 与 ||、is- 与 in- 检测以及其他一些操作符

a && b xor c 等价于 a && (b xor c)
a xor b in c 等价于 (a xor b) in c

局部函数

可以在一个函数中定义另一个函数,局部函数可以访问外部函数的变量

fun test1() {
    var name: String
    fun test2(): String {
        name = "hi"
        return name
    }
    test2()
}

尾递归函数

每次递归都会让方法入栈,直到终止条件触发时,每个方法才返回,方法入栈次数多,占用内存多,如果方法层级过多,则会出现栈内存溢出

在这里插入图片描述

对递归做了优化,结合了递归和迭代的功能
尾递归的原理是,在kotlin中用递归的写法,底层java代码是使用迭代方式
既能比较方便的使用递归,又减少了对内存的开销
函数前面加上tailrec关键字

在这里插入图片描述

//尾递归
//尾递归优化加上tailrec
tailrec fun sum2(n: Int, sum: Int = 0): Int {
    if (n <= 1) return sum + 1
    return sum2(n - 1, sum + n)
}

函数必须将其自身调用作为它执行的最后一个操作。在递归调用后有更多代码时,不能使用尾递归,并且不能用在 try/catch/finally 块中

高阶函数

高阶函数是将函数用作参数或返回值的函数

函数类型

声明函数类型

使用(Int)->String等一系列函数类型来处理函数的声明。Int表示函数类型的参数,String表示函数类型的返回值

  • (Int)->Unit
  • 带接收者A.(B)->C
  • 挂起函数的使用suspend (String)->Unit或者suspend A.(B)->C

获取函数类型

  • 匿名函数
fun(i:Int):String{}

val c: (Int) -> String = fun(i: Int): String {
    val k = i + 10
    return k.toString()
}

//核心就是:

(Int)->String = fun(i:Int):String{}
  • lambda表达式
val d: (Int) -> String = { i: Int ->
    ""//最后一行表示返回值
}

//核心
(Int)->String = {i-> ""}
  • 使用已有的函数引用,使用::进行引用
fun hi(i: Int): String {
    return ""
}

val f: (Int) -> String = ::hi


//扩展函数
fun Boolean.check(i: Int): String {
    return ""
}

fun check2(b: Boolean, i: Int): String {
    return ""
}

val g: Boolean.(Int) -> String = Boolean::check
val h: Boolean.(Int) -> String = ::check2
val k: (Boolean, Int) -> String = Boolean::check

//上面的扩展函数和函数类型可以互相转换
  • 自定义类实现函数类型接口
class Hero :(Int)->String{
    override fun invoke(p1: Int): String {
        return (p1-100).toString()
    }

}

val e = Hero()

函数类型的调用

函数类型变量调用()invoke()即可调用函数类型

f.invoke(x) 或者直接 f(x)

调用扩展函数类型,invoke的第一个参数是接收者类型或者用接收者.()

val my: Double.(String) -> Unit = fun Double.(s: String) {}

my.invoke(10.0, "my")
//或
90.9.my("my")

闭包

一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数称为闭包

fun test():()->Unit{
    var a = 10
    return {
        println(a)
        a++
    }
}

    val test = test()//()->Unit
    test()//10
    test()//11

带接收者函数类型

A.(B)->C
如果函数的参数是带接收者带函数类型,默认持有隐式作用域this

fun foo4(c: String.(name:Boolean) -> Unit){
    c.invoke("ooo",false)
}

foo4 {//有隐式this,并且有隐式it
   if (it){
       this+"000"
   }else{
       this+"111"
   }
   println(this)
}

使用扩展函数引用传递

fun foo4(c: String.(name:Boolean) -> Unit){
    c.invoke("ooo",false)
}

foo4(fun String.(b:Boolean){//this表示String

	}
)
//或者

fun String.ff(b:Boolean){//this

}

foo4(String::ff)

//或者

foo4{//this,it

}

有无接收者的函数类型可以互相引用

fun main() {
    val v1: Boolean.(Int) -> String = Boolean::f1
	//带接收者的类型相当于没有带接收者的第一个参数
    val v2: (Boolean, Int) -> String = Boolean::f1

    val v3: Boolean.(Int) -> String = ::f2
    val v4: (Boolean, Int) -> String = ::f2

    v4.invoke(true, 1)
    true.v3(1)
    v3.invoke(false, 2)

    Boolean::f1.invoke(false, 20)
    (Boolean::f1)(false, 20)
    (::f2)(false, 1)
    false.f1(10)
}

fun Boolean.f1(i: Int): String {
    return ""
}

fun f2(b: Boolean, i: Int): String {
    return ""
}

匿名函数

匿名函数是没有名字的常规函数,但只能用在表示函数类型,不能单独定义。

fun foo4(c: String.(name:Boolean) -> Unit){
    c.invoke("ooo",false)
}

foo4(fun(n:String,b:Boolean){})

lambda表达式

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

fun foo(s: String, callback: (Boolean) -> Unit) {

}

foo(""){}

如果函数的最后一个参数是函数类型,可以写到圆括号外面,如果函数参数只有一个函数类型的参数,可以省略圆括号

fun foo2(c:()->Unit){
    
}

foo2 {

    }

lambda表达式只有一个参数时,有隐式参数it,有多个参数时,需要显式声明。

lambda返回值是最后一行,不需要return

fun foo3(c: (Int) -> String){
    
}

foo3{
    val i1 = it + 10//隐式it
    i1.toString()//返回值
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值