Kotlin 第十四章:函数

Kotlin 第十四章:函数

在前面的文章中也是简单的学习过函数相关的知识,这篇文章,我跟大家一起来具体的学习一下函数相关的内容。

函数声明

在 Kotlin 中用关键字 fun 声明函数:

fun double(x: Int): Int {

}

函数用法

通过传统的方法调用函数

val result = double(2) 

通过 . 调用成员函数

Sample().foo() // 创建Sample类的实例,调用foo方法

参数

函数参数是用 Pascal 符号定义的 name:type。参数之间用逗号隔开,每个参数必须指明类型。

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

默认参数

函数参数可以设置默认值,当参数被忽略时会使用默认值。这样相比其他语言可以减少重载。

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size() ) {
...
}

默认值可以通过在 type 类型后使用 = 号进行赋值,重写方法的时候是可以把默认参数给替换掉的。

命名参数

在调用函数时可以参数可以命名。这对于那种有大量参数的函数是很方便的。

下面是一个例子:

fun reformat(str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ') {
...
}

我们可以使用默认参数

reformat(str)

然而当调用非默认参数是就需要像下面这样:

reformat(str, true, true, false, '_')

使用命名参数我们可以让代码可读性更强:

reformat(str,
    normalizeCase = true,
    uppercaseFirstLetter = true,
    divideByCamelHumps = false,
    wordSeparator = '_'
  )

如果不需要全部参数的话可以这样:

reformat(str, wordSeparator = '_')

注意,命名参数语法不能够被用于调用 Java 函数中,因为 Java 的字节码不能确保方法参数命名的不变性。

中缀符号

中缀表达式是操作符以中缀形式处于操作数的中间(例:3 + 4),使用中缀符号 infix 可以调用函数,但必须符合一些条件:

  • 必须是成员方法或者扩展函数
  • 函数只有一个参数
  • 使用infix关键字表示

举个栗子:

// 定义扩展函数
infix fun Int.iInfix(x: Int): Int  = this + x

fun main(args: Array<String>) {
    // 用中缀符号表示的扩展函数使用
    println("2 iInfix 1:${2 iInfix 1}") // 打印:2 iInfix 1:3
    // 与下面是相同的
    println("2.iInfix(1):${2.iInfix(1)}") // 打印:2.iInfix(1):3
}

不带返回值的参数

如果函数不会返回任何有用值,那么他的返回类型就是 UnitUnit 是一个只有唯一值 Unit 的类型.这个值并不需要被直接返回:

fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there!")
    // `return Unit` or `return` is optional
}

Unit 返回值也可以省略,比如下面这样:

fun printHello(name: String?) {
    ...
}

单表达式函数

当函数只返回单个表达式时,大括号可以省略并在 = 后面定义函数体

fun double(x: Int): Int = x*2

在编译器可以推断出返回值类型的时候,返回值的类型可以省略:

fun double(x: Int) = x * 2

变长参数

在 Java 中使用可变参数是这样写的:

private void getStr(String... params) {
      ...
}

而在 Kotlin 中使用可变参数(通常是最后一个参数)的话,是用 vararg 关键字修饰的:

fun <T> asList(vararg ts: T): List<T> {
    val result = ArrayList<T>()
    for (t in ts) // 在这里ts的类型是数组
        result.add(t)
    return result
}

使用的时候与 Java 一样:

val list = asList(1, 2, 3)

当我们调用 vararg 函数,不仅可以接收可以一个接一个传递参数,例如 asList(1, 2, 3),也可以将一个数组传递进去,在数组变量前面加 spread 操作符,就是 * 号:

val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4) // 表示(-1, 0, 1, 2, 3, 4)

局部函数

Kotlin 支持局部函数,比如在一个函数包含另一函数。

fun dfs(graph: Graph) {
  fun dfs(current: Vertex, visited: Set<Vertex>) {
    if (!visited.add(current)) return
    for (v in current.neighbors)
      dfs(v, visited)
  }

  dfs(graph.vertices[0], HashSet())
}

局部函数可以访问外部函数的局部变量(比如闭包)

fun dfs(graph: Graph) {
    val visited = HashSet<Vertex>()
    fun dfs(current: Vertex) {
        if (!visited.add(current)) return 
        for (v in current.neighbors)
            dfs(v)
    }
    dfs(graph.vertices[0])
}

局部函数甚至可以返回到外部函数

fun reachable(from: Vertex, to: Vertex): Boolean {
    val visited = HashSet<Vertex>()
    fun dfs(current: Vertex) {
        if (current == to) return@reachable true
        if (!visited.add(current)) return
        for (v  in current.neighbors)
            dfs(v)
    }
    dfs(from)
    return false
}

成员函数

成员函数是定义在一个类或对象里边的

class Sample() {
    fun foo() { print("Foo") }
}

成员函数可以用 . 的方式调用

Sample.foo()

尾递归函数

Kotlin 支持函数式编程的尾递归。这个允许一些算法可以通过循环而不是递归解决问题,从而避免了栈溢出。当函数被标记为 tailrec 时,编译器会优化递归,并用高效迅速的循环代替它。

计算的是数学上的余弦不动点。Math.cos 从 1.0 开始不断重复,直到值不变为止,结果是 0.7390851332151607 在Java中使用递归是这样写的:

private double findFixPoint(double x = 1.0) {
    if (x == Math.cos(x)) {
        return x;
    } else {
        findFixPoint(Math.cos(x));
    }
}

在 Kotlin 中是这样的:

private fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = Math.cos(x)
        if ( x == y ) return y
        x = y
    }
}

如果使用 Kotlin 的尾递归,代码可以这么写:

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

使用 tailrec 修饰符必须在最后一个操作中调用自己。在递归调用代码后面是不允许有其它代码的,并且也不可以在 try/catch/finall 块中进行使用。当前的尾递归只在 JVM 的后端中可以用

后记

函数还有好多没有学习的,比如:高阶函数、Lambda 表达式和内联函数等,今天的学习先暂时告一段落,下一篇文章一起来学习一下 高阶函数和 Lambda 表达式。

这篇文章中没有什么很难理解和消化的内容,好多内容和 Java 中区别不是很大,所以理解起来还是比较容易,不过呢还是希望给看官能够多多的提出自己的宝贵意见,我们一同进步~!

参考

Kotlin中文文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值