kotlin函数入门系列一

作者: 027f63d16800 | 来源:发表于2017-12-11 23:59 被阅读30次

    普通函数声明

    使用 func 关键字声明一个函数,像这样

    fun add(a:Int,b:Int):Int{
        return a+b
    }
    

    kotlin中,所有函数的参数都是val的,即不可变参数
    如果函数体只有一行代码,可以简洁点:

    fun add(a: Int, b: Int): Int = a + b
    

    更简单点,返回值自动推断:

    fun add(a: Int, b: Int) = a + b
    

    带默认值的函数

    可以在声明函数参数的时候,直接指定默认值,如果调用时没有传入,将使用默认值,带有默认值的参数可以在任何位置

    fun add(a: Int=1, b: Int) = a + b
    

    调用的时候,可以使用参数名=值的形式给出参数

    add(b=1)
    

    换个位置声明默认值:

    fun add(a: Int , b: Int=1) = a + b
    fun adds (a:Int,b:Int=1,c:Int)= a+b+c
    fun main(vararg args:String){
        add(1)    //自动匹配第一个参数
        adds (1,c=2)    //默认值之后的参数需要显示指出参数名
    }
    

    函数匹配优先级:

    fun add(a:Int) = a*a
    fun add(a: Int , b: Int=1) = a + b
    fun main(vararg args:String){
       println(add(3))  //输出 9 
    }
    

    当有多个函数匹配时,带默认值参数个数少的优先级越高,不带默认值的优先级最高

    可变参数

    kotlin中,使用 vararg 关键字来标识可变参数
    java一样,多个参数会被封装成数组赋值给a

    fun add(vararg a: Int, b: Int):Int{
        var sum :Int = 0
        a.forEach { 
            sum+=it
        }
        return sum+b
    }
    

    java不同的是,在java中我们可以直接将一个数组赋值给可变参数,这有时候会引起混淆,因此在kotlin中,我们需要显示使用运算符*将数组解构成元素
    比如我们可以这样调用上面的方法:

    fun main(vararg args: String) {
        var arr = IntArray(10) { it }
        add(*arr, b = 1)
    }
    

    注意,第二个参数我们需要明确指出他的参数名,否则他会被当作可变参数中的一个值

    使用lambda

    lambda是一种特殊的函数。和传统函数不同的是,他可以被存储,传递,并且可以捕获外部变量形成闭包。

    lambda的类型

    因为lambda本质上还是对象,因此他是有类型的。
    lambda的类型格式为:

    (参数列表)->返回值类型
    

    lambdabody结构为:

    {形参列表->
      语句
      ...
      最后一个语句的值为返回值(如果需要返回值)
    }
    

    比如:

    val max:(Int,Int)->Int = {a,b -> if (a>b) a else b}
    

    max用于比较两个整数,并返回他们中的最大者。因为这边接收了两个参数,因此我们需要在lambdabody中显示的为这两个参数指定一个名字,就像我们需要为函数指定形参名。
    上面的例子也可以这样写:

    val max =  { a:Int,b:Int-> if (a>b) a else b}  as (Int,Int)->Unit
    

    不过这是比较2b的写法了,使用aslambda进行类型转换,然后max的类型自动推出,这里我只是想说明lambda本质上还是个对象,因此一样可以进行类型转换。

    高阶函数

    lambda可以作为函数的参数或者返回值,举个例子:

    fun <T> forEach(list:List<T>,block:(t:T)->Unit){
        for (t in list){
            block(t)
        }
    }
    
    fun main(vararg args:String){
        var list = listOf(1,2,3,4,5)
        forEach(list){
            println(it)
        }
    }
    

    在上面的例子中,我们声明了一个forEach的函数,他的功能是遍历一个列表,并对列表中的每个元素调用指定的lambda,然后我们在main函数中调用它。
    值得注意的是,这里当我们的lambda是函数的最后一个参数时,我们可以将其写在()外面,当函数参数只有一个lambda时,可以直接省略()
    还有第二个要注意的是,我们使用了匿名参数,当lambda只有一个参数时,我们可以不用显示的指定一个参数名,而是使用默认的it来引用。

    扩展函数

    kotlin中,我们可以很方便的扩展某个类,为其增加方法:

    fun Int.compareWith(a: Int): Int {
        return when {
            this > a -> 1
            this < a -> -1
            else -> 0
        }
    }
    
    fun main(vararg args: String) {
        println(10.compareWith(4))
    }
    

    如上所示,声明一个扩展函数的语法很简单,只需要在方法名前面加上类名.,在方法中我们可以使用this来引用他,但是只能访问public的成员。这个类名我们使用receiver来描述它。
    扩展函数只是kotlin中众多语法糖中的一个,他并没有真正的扩展这个类,只是将方法的一个参数提到了方法名前面作为receiver

    fun Int.compareWith(a:Int):Int
    ===>
    fun compareWith(this:Int,a:Int):Int  
    

    所以调用扩展函数和普通的函数调用没有区别,函数的receiver本质上还是这个函数的参数,而不是这个方法的所有者,因此在调用时使用的是静态分派,并不支持多态。
    而且当扩展函数与类的方法冲突时,默认使用的是类的方法。

    结合泛型的扩展函数
    fun <T:Any> T?.toStr(){
        println(this?.toString()?:"this is a null ref")
    }
    fun main(vararg args:String){
        null.toStr()
    }
    

    正如上面的例子中所看到的,我们可以使用泛型参数作为函数的receiver,而且我们使用了T?,说明支持null

    函数参数使用扩展函数

    对刚刚的forEach函数稍加改造:

    fun <T> forEach(list:List<T>,block:T.()->Unit){
        for (t in list){
           t.block()
        }
    }
    
    fun main(vararg args:String){
        var list = listOf(1,2,3,4,5)
        forEach(list){
            println(this)
        }
    }
    

    注意在声明函数参数时,我们使用了T.()->Unit,也就是声明了一个具有receiverlambda

    相关文章

      网友评论

        本文标题:kotlin函数入门系列一

        本文链接:https://www.haomeiwen.com/subject/wzktvxtx.html