Kotlin 2.1.0 入门教程(二)
函数
一个带有两个 Int
参数并返回 Int
类型的函数。
fun sum(a: Int, b: Int): Int {
return a + b
}
函数体可以是一个表达式,其返回类型可以省略,省略会被自动推断。
fun sum(a: Int, b: Int) = a + b
fun sum(a: Int, b: Int): Int = a + b
一个不返回值的函数。
Unit
类型表示函数没有返回值。Unit
类似于 Java 中的 void
,但它是 Kotlin 中的一个实际类型。如果函数返回 Unit
,则可以省略 Unit
声明。
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
在声明函数参数时,可以使用尾随逗号。
fun func(a: Int, b: Int,) = 0
默认参数
函数参数可以有默认值,当您跳过相应参数时会使用这些默认值。这可以减少重载函数的数量。
fun read(b: ByteArray, off: Int = 0, len: Int = b.size,) {}
重写方法时总是使用基类方法的默认参数值。当重写一个带有默认参数值的方法时,必须从签名中省略默认参数值。
open class A {
open fun foo(i: Int = 10) {}
}
class B : A() {
override fun foo(i: Int) {} // 不允许设置默认值。
}
如果一个默认参数位于没有默认值的参数之前,则只能通过使用命名参数调用函数来使用默认值。
fun foo(bar: Int = 0, baz: Int,) {}
foo(baz = 1) // 使用了默认值 bar = 0。
fun main() {
func(1, 2) // a = 1, b = 2
func(b = 2) // a = -1, b = 2
// func(1) // error
}
fun func(a: Int = -1, b: Int,) = println("a = $a, b = $b")
如果默认参数后面的最后一个参数是 lambda 表达式,您可以将其作为命名参数传递,或放在括号外。
fun main() {
foo { println("func1") } // a = 0, b = 1, func = func1
foo(1) { println("func2") } // a = 1, b = 1, func = func2
foo(1, 2) { println("func3") } // a = 1, b = 2, func = func3
foo(func = { println("func4") }) // a = 0, b = 1, func = func4
foo(1, func = { println("func5") }) // a = 1, b = 1, func = func5
foo(1, 2, func = { println("func6") }) // a = 1, b = 2, func = func6
foo(1, 2, { println("func7") }) // a = 1, b = 2, func = func7
}
fun foo(a: Int = 0, b: Int = 1, func: () -> Unit,) {
print("a = $a, b = $b, func = ")
func()
}
命名参数
在调用函数时,可以为一个或多个参数命名。
当一个函数有许多参数且难以将值与参数关联时,这非常有用。
在函数调用中使用命名参数时,可以自由更改参数的顺序。如果想使用参数的默认值,可以直接省略这些参数。
fun main() {
foo(1)
foo(a = 1)
foo(1, c = false)
foo(a = 1, c = false, b = true)
}
fun foo(a: Int, b: Boolean = true, c: Boolean = true) {}
fun main() {
foo(1)
foo(2, c = 1)
foo(3, c = 1, b = 2, d = 3)
foo(4, 4, d = 5)
}
fun foo(a: Int, b: Int = 0, c: Int = 0, d: Int = 0) {}
可以使用展开运算符 *
传递带有名称的可变数量参数 vararg
。
fun foo(vararg strings: String) {}
foo(strings = *arrayOf("a", "b", "c"))
在 JVM 上调用 Java 函数时,不能使用命名参数语法,因为 Java 字节码并不总是保留函数参数的名称。
返回 Unit
如果一个函数不返回值,那么它的返回类型是 Unit
。
Unit
是一个只有一个值的类型:Unit
,这个值不需要显式返回。
fun main() {
func1()
func2()
func3()
func4()
func5()
}
fun func1(): Unit {
return
}
fun func2(): Unit {
return Unit
}
fun func3() {
return
}
fun func4(): Unit {
}
fun func5() {
}
可变数量参数 vararg
可以使用 vararg
修饰符标记函数的参数(通常是最后一个参数)。
在这种情况下,可以向函数传递可变数量的参数。
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts)
result.add(t)
return result
}
val list = asList(1, 2, 3)
在函数内部,类型为 T
的 vararg
参数 ts
被视为 T
的数组,如上例所示,其中 ts
变量的类型是 Array<out T>
。
只有一个参数可以被标记为 vararg
。vararg
参数通常应放在参数列表的最后。
如果 vararg
参数不是列表中的最后一个参数,则可以使用命名参数语法为后续参数传递值,或者如果参数是函数类型,则可以在括号外传递 lambda 表达式。
fun printAll(prefix: String, vararg messages: String, suffix: String, func: () -> Unit) {
println(prefix)
for (message in messages) {
println(message)
}
println(suffix)
func()
}
fun main() {
// Start
// Hello
// World
// End
// OK
printAll("Start", "Hello", "World", suffix = "End") { println("OK") }
}
当调用 vararg
函数时,可以单独传递参数,例如 asList(1, 2, 3)
。
如果已经有一个数组并希望将其内容传递给函数,请使用展开运算符(在数组前加上 *
)。
fun printAll(vararg messages: String) {
for (message in messages) {
println(message)
}
}
fun main() {
val messages = arrayOf("Hello", "World", "Kotlin")
printAll(*messages)
}
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
如果想将基本类型数组传递给 vararg
,需要使用 toTypedArray()
函数将其转换为常规(类型化)数组。
基本类型数组(如 IntArray
、DoubleArray
等)不能直接传递给 vararg
参数,必须先转换为常规(类型化)数组。
fun <T> prints(vararg numbers: T) {
for (number in numbers) {
println(number)
}
}
fun main() {
val intArr = intArrayOf(1, 2, 3).toTypedArray()
prints(*intArr)
}
fun <T> func1(vararg para: T) {
println(para is Array<T>)
}
fun func2(vararg para: Int) {
println(para is IntArray)
}
fun main() {
val intArr = intArrayOf(1, 2, 3)
func1(*intArr.toTypedArray()) // true
func2(*intArr) // true
}
中缀表示法
使用 infix
关键字标记的函数可以通过中缀表示法调用(省略点和调用时的括号)。
infix
函数必须满足以下要求:
-
它们必须是成员函数或扩展函数。
-
它们必须只有一个参数。
-
参数不能是可变数量参数
vararg
,也不能有默认值。
infix fun Int.addOne(x: Int) = x + 1
fun main() {
println(2 addOne 1) // 2
println(2.addOne(1)) // 2
}
infix
函数调用的优先级低于算术运算符、类型转换和 rangeTo
运算符。以下表达式是等价的:
-
1 addOne 2 + 3
等价于1 addOne (2 + 3)
-
0 until n * 2
等价于0 until (n * 2)
-
xs union ys as Set<*>
等价于xs union (ys as Set<*>)
另一方面,infix
函数调用的优先级高于布尔运算符 &&
和 ||
、is
和 in
检查以及其他一些运算符。以下表达式也是等价的:
-
a && b xor c
等价于a && (b xor c)
-
a xor b in c
等价于(a xor b) in c
请注意,infix
函数始终需要指定接收者和参数。
当使用中缀表示法在当前接收者上调用方法时,请显式使用 this
。这是为了确保解析的明确性。
class Foo {
infix fun add(s: String) {
}
fun build() {
this add "abc" // ok
add("abc") // ok
add "abc" // error
}
}
函数作用域
Kotlin 函数可以在文件的顶层声明,这意味着不需要像在 Java 等语言中那样创建一个类来存放函数。
除了顶层函数外,Kotlin 函数还可以作为成员函数和扩展函数在局部声明。
// 顶层函数。
fun printMessage(message: String) {
println(message)
}
class Example {
// 成员函数。
fun doSomething() {
println("Doing something")
}
}
// 扩展函数。
fun Example.printAdditionalInfo() {
println("Additional info")
}
fun main() {
printMessage("Hello, World!") // 调用顶层函数。
val example = Example()
example.doSomething() // 调用成员函数。
example.printAdditionalInfo() // 调用扩展函数。
}
局部函数
Kotlin 支持局部函数,即函数内部定义的函数。
fun outerFunction() {
println("outerFunction")
// 局部函数。
fun innerFunction() {
println("innerFunction")
}
innerFunction() // 调用局部函数。
}
fun main() {
// outerFunction
// innerFunction
outerFunction()
}
局部函数可以访问外部函数的局部变量(闭包)。
fun outerFunction() {
var visited = false // 外部函数的局部变量。
println("visited = $visited")
fun innerFunction() {
visited = true // 访问并修改外部函数的变量。
println("visited = $visited")
}
innerFunction() // 调用局部函数。
println("visited = $visited")
}
fun main() {
// visited = false
// visited = true
// visited = true
outerFunction()
}
尾递归函数
当一个函数被标记为 tailrec
并满足所需的形式条件时,编译器会优化递归,将其替换为快速且高效的基于循环的版本。
尾递归函数可以通过编译器优化为循环,从而避免递归调用导致的栈溢出问题。
tailrec fun factorial(n: Int, result: Int = 1): Int {
return if (n == 1) result else factorial(n - 1, n * result)
}
fun main() {
println(factorial(5)) // 120
}
要符合 tailrec
修饰符的条件,函数必须将调用自身作为其执行的最后一个操作。
在递归调用之后还有代码、在 try / catch / finally
块中或开放函数中,不能使用尾递归。
目前,Kotlin 对 JVM 和 Kotlin/Native 支持尾递归。
原文地址:https://blog.csdn.net/qq_19661207/article/details/145198936
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!