函数入门
函数的定义和调用
函数的定义语法如下:
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))
}
网友评论