kotlin之函数

小灰灰 2022-10-25 14:25 314阅读 0赞

kotlin之函数

函数的声明

使用fun关键字来声明函数:

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

函数的使用

全局函数(其实就是函数声明所在类的静态方法)的使用:

  1. val result = double(2)

类的成员方法的使用:

  1. Stream().read() // create instance of class Stream and call read()

参数

参数的定义:

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

默认参数

默认参数能够减少类中重载的方法,默认参数的定义:

  1. fun read(
  2. b: Array<Byte>,
  3. off: Int = 0,
  4. len: Int = b.size,
  5. ) { /*...*/ }

对于重写的方法来说,子类所拥有的重写方法拥有与父类一样的默认参数值,子类重写父类中带有默认参数的方法时,方法中必须将参数的默认值省略掉。

  1. open class A {
  2. open fun foo(i: Int = 10) { /*...*/ }
  3. }
  4. class B : A() {
  5. override fun foo(i: Int) { /*...*/ } // No default value is allowed
  6. }

如果一个无默认值的参数位于有默认值参数的前面,那么要想使用默认值,就必须使用具名参数。

  1. fun foo(
  2. bar: Int = 0,
  3. baz: Int,
  4. ) { /*...*/ }
  5. foo(baz = 1) // The default value bar = 0 is used

如果默认参数后面的最后一个参数是lambda表达式,那么可以使用具名参数或者将lambda表达式位于括号外。

  1. fun foo(
  2. bar: Int = 0,
  3. baz: Int = 1,
  4. qux: () -> Unit,
  5. ) { /*...*/ }
  6. foo(1) { println("hello") } // Uses the default value baz = 1
  7. foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1
  8. foo { println("hello") } // Uses both default values bar = 0 and baz = 1

具名参数

在调用函数时,函数参数是可以具名的,当一个函数拥有大量的参数或者拥有一些默认参数时,这种调用方式是比较方便的。

  1. fun reformat(
  2. str: String,
  3. normalizeCase: Boolean = true,
  4. upperCaseFirstLetter: Boolean = true,
  5. divideByCamelHumps: Boolean = false,
  6. wordSeparator: Char = ' ',
  7. ) {
  8. /*...*/
  9. }

如果同时使用了位置参数和具名参数,那么前面必须是相连的位置参数,后面必须是相连的具名参数。

  1. reformat('This is a short String!', upperCaseFirstLetter = false, wordSeparator = '_')

可变参数可以借助为spread operator以具名参数的方式传递:

  1. fun foo(vararg strings: String) { /*...*/ }
  2. foo(strings = *arrayOf("a", "b", "c"))

在kotlin中调用java方法时不能使用具名参数,因为java的字节码中并不总是保留方法的参数名。

返回Unit的函数

如果函数没有返回值,可以返回Unit来代表没有返回值:

  1. fun printHello(name: String?): Unit {
  2. if (name != null)
  3. println("Hello $name")
  4. else
  5. println("Hi there!")
  6. // `return Unit` or `return` is optional
  7. }

Unit返回类型可以省略:

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

单表达式函数

如果一个函数只会返回一个简单的表达式,那么花括号都可以省略:

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

返回值也无需指定,编译器能够自动推导出来:

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

显示返回类型

有方法体的函数必须显示的指定返回类型,除非方法返回Unit才可以省略,kotlin不会去自动推导有方法体的函数,因为这些方法通常拥有很复杂的业务流程,返回值对阅读代码的人来说就不那么明显了,有时候,对于编译器来说同样如此。

可变参数

方法的参数可以用vararg来修饰,表示一个可变的参数类型:

  1. fun <T> asList(vararg ts: T): List<T> {
  2. val result = ArrayList<T>()
  3. for (t in ts) // ts is an Array
  4. result.add(t)
  5. return result
  6. }

一个方法中只允许一个参数为vararg,通常作为最后一个参数,如果不是最后一个参数,那么后面的参数必须使用具名参数来调用,如果最后一个参数是一个函数类型,还可以通过圆括号外声明lambda表达式来调用。

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

中缀符号

函数还可以通过中缀符号来调用,函数需要满足以下条件:

  1. 必须是成员函数或者扩展函数
  2. 函数必须只有一个参数
  3. 函数不能是可变参数或者有默认值

    infix fun Int.add(other: Int) = this + other

    fun main() {

    1. println(5 add 6)

    }

尾递归

kotlin中,如果某个函数的末尾又调用了函数自身,这种就称为尾递归函数。尾递归函数需要在fun前面添加tailrec。

尾递归函数会使用循环的方式替代递归,从而避免栈溢出。尾递归不能在异常处理的try、 catch 、 finally块中使用。

例如:计算阶乘的函数。

  1. fun fact(n: Int): Int {
  2. return if (n == 1) {
  3. 1
  4. } else {
  5. n * fact(n - 1)
  6. }
  7. }

上面函数将调用自身作为其执行体的最后一行代码,且递归调用后没有更多代码,因此可以将该函数改为尾递归语法。此时,上面函数可改为如下形式

  1. tailrec fun factRec(n: Int, total : Int= 1): Int = if (n == 1) total else factRec(n - 1 , total * n)

与普通递归相比,编译器会对尾递归进行修改,将其优化成一个快速而高效的基于循环的版本,这样就可以减少可能对内存的消耗。

发表评论

表情:
评论列表 (有 0 条评论,314人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Kotlin函数

    函数和方法指的是同一个东西 语法规则 fun(function的简写)是定义函数的关键字,无论定义什么函数,都需要用fun来声明 fun后面是方法名,可以随意起,但是

    相关 Kotlin系列扩展函数

    简述: 今天带来的是Kotlin浅谈系列的第五弹,这讲主要是讲利用Kotlin中的扩展函数特性让我们的代码变得更加简单和整洁。扩展函数是Kotlin语言中独有的新特性,利用它可