Kotlin学习(十六)—— 函数

kotlin的函数基础比较简单,这里很简要的说明一下。

函数声明

这个函数声明就随意示范一下吧:
函数的声明:fun 方法名 (形参列表):返回值类型 { 方法体}

fun double(x: Int): Int {
    return 2*x
}

函数用法:

fun main(args: Array<String>) {
    var sum = sum(1, 6)
    println(sum)
}

代码调用了上面声明的函数

参数

Kotlin函数参数使⽤ Pascal 表⽰法定义,即 name: type。参数⽤逗号隔开。每个参数必须有显式类型。

fun powerOf(number: Int, exponent: Int) {
    ……
}

默认参数

函数参数可以有默认值,当省略相应的参数时使⽤默认值。与其他语⾔相⽐,这可以减少重载数量。
默认值通过类型后⾯的 = 及给出的值来定义。

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

覆盖⽅法总是使⽤与基类型⽅法相同的默认参数值。当覆盖⼀个带有默认参数值的⽅法时,必须从签名中省略默认参数

open class  B<T>{
    open fun read(array : Array<T>, off : Int = 0, len : Int = array.size ){
        for (a in array){
            println(a)
        }
    }
}
class C<E> : B<E>() {
    override fun read(array: Array<E>, off: Int, len: Int) {
        for (a in array){
            println("$a +  ")
        }
    }
}
fun main(args: Array<String>) {
    C<Int>().read(arrayOf(3, 4, 6, 76, 91, 67))
}

如果⼀个默认参数在⼀个无默认值的参数之前,那么该默认值只能通过使⽤命名参数调⽤该函数来使用

fun add(a:Int = 1,b:Int):Int{ //参数b之前有默认参数
    return a+b
}
fun main(args: Array<String>) {
    println(add(2,2)) //这样调用没有问题
    //但是如果我想使用a的默认值那么就要使用命名参数
    println(add(b=2))
}

不过如果最后⼀个 lambda 表达式参数从括号外传给函数函数调用,那么允许默认参数不传值

fun add(a: Int = 1,b: Int = 2,show:(result:Int) -> Unit){
    show(a+b)
}
fun main(args: Array<String>) {
    add(2){result -> println(result)} //这个时候是a被赋予值,b使用默认值
    add { result -> println(result)}  //这个时候是都是用的是默认值
}

命名参数,这是在函数调用的时候,明确调用参数,从而提高程序的可读性, 有时候我们设定默认值的时候可能可读性很差。

fun <T> readArray(array : Array<T>, off : Int = 0,len : Int = array.size){
    if (off >= 0 && len <= array.size && len >= 0 && len + off <= array.size){
        for (i in off ..(len + off - 1)){
            println(array[i])
        }
    }
}
//这样我我们调用者就知道函数的含义了
fun main(args: Array<String>) {
    readArray(arrayOf(13,3,45,67,98,32,43),off = 2, len =4)
}

返回值为Unit的函数

如果⼀个函数不返回任何有⽤的值,它的返回类型是 Unit 。Unit 是⼀种只有⼀个值⸺ Unit 的类型。这个值不需要显式返回

fun sayHello(name :String?):Unit{
    if (name != null){
        println("hello $name")
    }else{
        println("hello")
    }
    //return Unit or return可选
}
//上面的相当于下面的函数
fun sayHello(name :String?){
    if (name != null){
        println("hello $name")
    }else{
        println("hello")
    }
}

单表达式的函数

当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可(这个很方便,大大简化了代码的编写)
下面的代码我们没有设置返回值的类型,因为表达式能推断出来。

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

注意:具有块代码体的函数必须始终显式指定返回类型,除非他们旨在返回 Unit ,在这种情况下它是可选的。Kotlin 不推断具有块代码体的函数的返回类型,因为这样的函数在代码体中可能有复杂的控制流,并且返回类型对于读者(有时甚⾄对于编译器)是不明显的。

可变函数参数

函数的参数(通常是最后⼀个)可以用 vararg 修饰符标记

fun <T> asList(vararg items : T):List<T>{
    var list = ArrayList<T>()
    for (i in items){
        list.add(i)
    }
    return list
}

fun main(args: Array<String>) {
    var list = asList("hello","hi","love")
    println(list)
    //另外还可以延伸的传入参数,如吧一个数组传入,前面使用*号,这里叫做伸展操作符
    var array = arrayOf("tom","jian","nihao")
    var list1 = asList("1",*array)
    println(list1)
}

在函数内部,类型 T 的 vararg 参数的可见方式是作为 T 数组,即上例中的 ts 变量具有类型 Array 。只有⼀个参数可以标注为 vararg 。如果 vararg 参数不是列表中的最后⼀个参数,可以使⽤命名参数语法传递其后的参数的值,或者,如果参数具有函数类型,则通过在括号外部传⼀个 lambda。
当我们调⽤ vararg -函数时,我们可以⼀个接⼀个地传参,例如 asList(1, 2, 3) ,或者,如果我们已经有⼀个数组并希望将其内容传给该函数,我们使⽤伸展(spread)操作符(在数组前⾯加 * )(代码如上):

函数的中缀表示法

使用中缀表示法的三个条件 1.他们是成员函数或者是扩展函数 2.他们只有一个参数 3 他们使用infix标注

infix fun Int.add1(b : Int):Int{
    return this + b
}
fun main(args: Array<String>) {
    var a = 1
    var b = 2
    var c = 1.add1(3)  //调用中缀表示法的函数调用,或者 a add b 的调用形式也可以
    println(c)
}

函数作用域

局部函数

Kotlin ⽀持局部函数,即⼀个函数在另⼀个函数内部

fun outer(){
    var a = 1
    var b = 4
    fun add(a: Int,b: Int):Int{
        return a + b  
    }
    println(add(a , b))
}
fun main(args: Array<String>) {
    outer()
}
fun outer(){
    var a = 1
    var b = 4
    fun add():Int{
        return a + b  //局部函数可以访问外部函数的局部变量
    }
    println(add())
}

fun main(args: Array<String>) {
    outer()
}

关于成员函数(定义在类中),和泛型函数,其他章都有提到过,所以这里省略掉。

尾递归函数

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

tailrec fun findFixPoint(x: Double = 1.0): Double
    = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
//这段代码计算余弦的不动点(fixpoint of cosine),这是⼀个数学常数。它只是重复地从 1.0 开始调⽤ Math.cos,直到结果不再改变,产⽣
//0.7390851332151607的结果
//要符合 tailrec 修饰符的条件的话,函数必须将其⾃⾝调⽤作为它执⾏的最后⼀个操作。在递归调⽤后有更多代码时,不能使⽤尾递归,并且不能⽤在
//try/catch/finally 块中。⽬前尾部递归只在 JVM 后端中⽀持。
fun main(args: Array<String>) {
    var x = findFixPoint(Math.PI/2)
    println(x)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值