您现在的位置是:首页 >学无止境 >kotlin教程4:函数进阶网站首页学无止境

kotlin教程4:函数进阶

微小冷 2023-07-02 00:00:03
简介kotlin教程4:函数进阶

kotlin教程:编程基础💎数据结构💎面向对象

可变参数

kotlin的函数定义非常灵活,既可以按照顺序传参,也可以通过参数名传参,而且可以设置参数默认值,这些在基础教程中已经讲过了。

此外,kotlin中用vararg修饰的参数,为长度可变的参数列表

fun printLst(vararg ts: Int){
    for(t in ts){
        println(t)
    }
}

printLst(1,2,3)
/*
1
2
3
*/

尾递归函数

递归是一种常用的编程技巧,就像之前写的递归式阶乘

fun fac(n:Int):Int{return if(n>1) n*fac(n-1) else 1}

但递归有一个很重要的缺点,即每次调用都要在栈中保存上一个函数的返回地址,如果递归层数太多,会导致栈溢出,所以很多时候会将递归算法改写成动态规划。

为了解决递归问题,kotlin提供了尾递归方案,即通过tailrec修饰的函数,如果在函数的最后一行调用自身,那么编译器将自动将递归函数转成迭代形式,而无需担心堆栈错误。

为了理解什么是尾递归,下面以斐波那契数列举个例子

fun fib(n:Int):Int{
    if(n<3)
        return 1
    else
        return fib(n-1)+fib(n-2)
}
fun main(){
    println(fib(215))
}

这个函数尽管在最后一行调用了自身,但调用自身后还有一个相加的操作,所以是不符合尾递归的要求的。

对此可将其改写为

fun fib(n:Long, a: Long, b: Long): Long {
    if (n < 1) return a
    else return fib(n-1, b, a + b)
}

这就是尾递归的形式。对比这两种不同的递归方案可以发现,第一种运行之后会卡住,在短时间内没法得出结果,后者则轻而易举地得出了。

>kotlin test.jar
319982248

当然,这个过程并没有使用tailrec关键字,所以当n的值比较大的时候一样会出问题

fun main(){
    println(fib(12000, 1, 1))
}

会报这个错误

Exception in thread "main" java.lang.StackOverflowError
        at TestKt.fib(test.kt:3)

下面可测试一下编译优化的效果

tailrec fun fib(n:Long, a: Long, b: Long): Long {
    if (n < 1) return a
    else return fib(n-1, b, a + b)
}

fun main(){
    println(fib(12000, 1, 1))
}

编译运行,顺利得出结果

>kotlin test.jar
3221758877563775297

函数式

所谓函数式,从敲代码的角度出发,就是把函数作为一种数据类型,可以自由地作为其他函数的参数与返回值。

由于Kotlin中,函数中所有的参数和返回值都要声明数据类型,所以,函数在作为参数传递时,也要标明函数的输入输出返回值,例如下面代码是函数作为参数的一个例子

fun testFunc(func:(Int)->Int) : (Double)->Double{
    return {a:Double -> func(a.toInt()).toDouble()}
}

fun test1(func:(Int)->Int):Int{
    return func(5)
}

其中,func:(Int)->Int为输入参数,func为参数名,(Int)->Intfunc作为一种函数的输入输出声明,表示func是一个输入Int输出Int的函数。

(Double)->DoubletestFunc的返回值类型,表示一个输入Double输出Double函数。

换言之testFunc的功能是,将一个输入输出均为整型的函数,转化为输入输出均为浮点型的函数。

return{ -> }是一个匿名函数,这个在最开始介绍函数的时候就已经讲过了。

接下来测试一下,先新建一个输入整型输出整型的函数

fun square(a:Int):Int{return a*a}
square(3)   // 返回值 kotlin.Int = 9
square(3.0) //报错

然后转换,需要注意,当函数作为参数传递时,需要用::标识

testFunc(::square)(3.0) //返回值9.0

也可以新建一个函数

val dSquare = testFunc(::square)
dSquare(3.0)    //kotlin.Double = 9.0
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。