函數入門
函數的定義和調用
函數的定義語法如下:
fun 函數名(形參列表):返回值類型{
//函數體
}
kotlin聲明函數必須使用fun關鍵字
函數的返回值可以是kotlin所允許的任何數據類型,如何聲明瞭函數的返回值類型,則函數體必須有一條有效的return語句,該語句返回了一個變量或者表達式,如果沒有返回值則有如下2種聲明方式:
- 省略“:返回值類型”部分
- 使用“:Unit”指定返回Unit代表沒有返回值,相當於java中的void
函數的形參列表用於定義該函數可以接受的參數,形參列表由多組“形參名:形參類型”組合而成,中間以逗號隔開。
fun max(x: Int, y: Int): Int {
val z = if (x > y) x else y
return z
}
fun sayHi(name: String): String {
return "${name} ,你好!"
}
fun foo() {
println("執行foo()函數")
}
fun sayHello(name: String): Unit {
print("${name},hello!")
}
fun main(args: Array<String>) {
var a = 6
var b = 9
println("最大值是: ${max(a, b)}")
print(sayHi("xq"))
foo()
sayHello("sq")
}
遞歸函數
在一個函數體內調用它自身,被稱爲函數的遞歸。
//遞歸函數
fun fn(n: Int): Int {
when (n) {
0 -> return 1
1 -> return 4
else -> return 2 * fn(n - 1) + fn(n - 2)
}
}
fun main(args: Array<String>) {
println("fn(10)的結果是${fn(10)}")
}
單表達式函數
在某些情況下,函數只返回單個表達式,此時可以省略花括號並在等號後指定函數體即可,這種方式被稱爲單表達式函數。對於單表達式函數而言,編譯器可以推導出函數的返回值類型,因此可以省略不寫。
//單表達式函數
fun area(x: Double, y: Double): Double = x + y
fun product(x: Double, y: Double) = x * y
fun main(args: Array<String>) {
println("1.2 + 2.5 = ${area(1.2, 2.5)}")
println("1.2 * 2.5 = ${product(1.2, 2.5)}")
}
函數的形參
命名參數
kotlin函數的參數名不是無意義的,kotlin允許調用函數時通過名字來傳入參數值。
注意在調用函數時混合使用命名參數和位置參數時,那麼命名參數必須位於位置參數的後面。
//函數的形參
//命名函數
fun girth(width: Double, height: Double): Double {
println("width: ${width},height: ${height}")
return 2 * (width + height)
}
fun main(args: Array<String>) {
//傳統調用函數的方式,根據位置傳入參數
girth(3.5, 4.9)
//根據參數名來傳入參數
girth(width = 3.5, height = 4.9)
//使用命名參數是可交換位置
girth(height = 4.9, width = 3.5)
//部分使用命名參數,部分使用位置參數 混合使用時命名參數必須位於位置參數之後
girth(3.5, height = 4.9)
}
形參默認值
在某些情況下,程序需要在定義函數時爲一個或多個形參指定默認值,這樣調用函數時就可以省略該形參,而直接使用默認值。爲形參指定默認值的語法如下:
形參名: 形參類型 = 默認值
如果在定義函數時將有默認值的參數放在了普通參數的前面,並且不想爲默認參數重新傳入參數值,那麼就只能使用命名參數爲其他參數傳入參數值。所以不建議這種寫法。
//形參默認值
fun sayHi(name: String = "xq", msg: String = "welcome") {
println("name: $name ,msg: $msg")
}
fun printTriangle(height: Int = 5, char: Char) {
for (i in 1..height) {
for (j in 0 until height - 1) {
print(" ")
}
for (j in 0 until 2 * i - 1) {
print(char)
}
println()
}
}
fun main(args: Array<String>) {
//全部使用默認值
sayHi()
//只有msg使用默認值
sayHi("xy")
//2個都不使用默認值
sayHi("sqq", "hi")
//只有name使用默認值
sayHi(msg = "你好")
printTriangle(6, '@')
printTriangle(7, char = '#')
printTriangle(char = '*')
}
尾遞歸函數
kotlin還支持一種尾遞歸函數的編程方式,當函數將調用自身作爲它執行的最後一行代碼,且遞歸調用之後沒有更多代碼時,可以使用尾遞歸語法。另外尾遞歸不能再異常處理的try,catch,finally中使用,尾遞歸需要使用tailrec修飾。
//尾遞歸函數
fun fact(n: Int): Int {
return when (n) {
1 -> 1
else -> n * fact(n - 1)
}
}
tailrec fun factRec(n: Int, total: Int = 1): Int =
//if (n == 1) total else factRec(n - 1, total * n)
when (n) {
1 -> total
else -> factRec(n - 1, total * n)
}
fun main(args: Array<String>) {
println("fact(10): ${fact(10)}")
println("factRec(10):${factRec(10)}")
}
個數可變的形參
kotlin允許定義個數可變的參數,從而爲函數指定數量不確定的形參,如果在定義函數時,在形參的類型前面添加了vararg修飾,則表明該形參可以接受多個參數值,多個參數值被當做數組傳入。
kotlin允許個數可變的形參處於形參列表的任何位置,但是要求一個函數最多只能有一個個數可變的形參,如果個數可變的形參位於參數列表的第一個,因此如果給後面參數賦值時必須使用命名參數。
//個數可變的形參
fun test(a: Int, vararg books: String) {
for (b in books) {
println(b)
}
println(a)
}
fun main(args: Array<String>) {
test(2, "java", "kotlin")
}
函數重載
kotlin允許定義多個同名函數,只要它們的形參列表或者返回值類型不同就行。如果程序包含了2個或者以上函數名相同,但是僅有參數列表不同的函數,就被成爲函數重載。
fun test(a: Int, vararg books: String) {
for (b in books) {
println(b)
}
println(a)
}
//函數的重載
fun test() {
println("函數的重載,上面是有參的函數")
}
fun main(args: Array<String>) {
test(2, "java", "kotlin")
test()
}
局部函數
之前我們所看到的函數都是在全局範圍內定義的,它們都是全局函數,kotlin還支持在函數體內部定義函數,這種函數稱爲局部函數。
在默認的情況下,局部函數都是對外部隱藏的,局部函數只能在其封閉的函數體內有效,其封閉函數也可以返回局部函數,以便程序在其他作用域中使用局部函數。
//局部函數
fun mathFunc(type: String, nn: Int): Int {
fun square(n: Int): Int {
return n * n
}
fun cube(n: Int): Int {
return n * n * n
}
when (type) {
"square" -> return square(nn)
"cube" -> return cube(nn)
else -> return 0
}
}
fun main(args: Array<String>) {
println(mathFunc("square", 3))
}