Kotlin基础二(函数)
再长的路,一步步也能走完,再短的路,不迈开双脚也无法到达。
今天学习了下函数,与Java相同的函数定义以及方法就省略了,今天主要讲下Kotlin中独有的函数或者与Java不同的地方(部分还没有学习到,后续再补充),开干。
一. 函数语法
函数声明 函数名称([参数名称:参数类型,参数名称:参数类型]):返回值类型{
执行语句
…
return 返回值
}
二. 单表达式函数
如果函数体中只有一行代码,则可以把包裹函数体的花括号{}替换为等号“=”,把函数体放在等号“=”的后面,这样的函数称为单表达式函数
fun add(a: Int, b: Int): Int = a + b
// 单表达式还可以省略函数的返回值类型
fun add(a: Int, b: Int) = a + b
三. 函数参数
1. 具名参数
指在调用函数时显示指定形参的名称,这样即使形参和实参的顺序不一致也不会有任何影响,因为已经明确指定了每个形参对应的实参,这样有助于提高代码的可读性
class Person(val name: String,val age : Int)
fun main() {
val person = Person(name = "张三",age = 18)
}
2. 默认参数
概念:指在定义函数时,可以给函数中的每一个形参指定一个默认的实参
优势:可以减少重载数量
class Student(val name : String = "张三",val age: Int)
fun main() {
val student = Student(age = 18)
}
注意:当覆盖⼀个有默认参数值的⽅法时,必须从签名中省略默认参数值
open class A {
open fun foo(i: Int = 10) {}
}
class B : A() {
override fun foo(i: Int) {} // 不能有默认值
}
3. 可变参数
可变参数通过vararg关键字标识,我们可以将其理解为数组。可变参数通常声明在形参列表中的最后位置,如果不声明在最后位置,那么可变参数后面的其他参数都需要通过命名参数的形式进行传递。
// 可变参数
class Num(vararg num : Int) {
//初始化
init {
var result = 0
// 循环
num.forEach {
result+= it
}
println("result:$result")
}
}
// 调用方式
val num = Num(1,2,3)
由于可变参数实质上就是数组,因此,可以直接使用数组存放可变参数,在传递时使用数组即可,这样更加直观方便。
// 传递数组
val intArr = intArrayOf(1,2,3)
// 注意要使用*展开数组(注意只能展开数组,不能展开集合)
val num2 = Num(*intArr)
总结-Kotlin中的可变参数与Java中的可变参数的对比
Kotlin中可变参数规则:
- 可变参数可以出现在参数列表的任意位置;
- 可变参数是通过关键字vararg来修饰;
- 可以以数组的形式使用可变参数的形参变量,实参中传递数组时,需要使用“*”前缀操作符。
Java中可变参数规则:
- 可变参数只能出现在参数列表的最后;
- 用“…”代表可变参数,“…”位于变量类型与变量名称之间;
- 调用含有可变参数的函数时,编译器为该可变参数隐式创建一个数组,在函数体中以数组的形式访问可变参数。
3. Kotlin特有函数
1. 顶层函数
顶层函数又称为包级别函数,可以直接放在某一个包中,而不像Java一样必须将函数放在某一个类中,函数可以独立存在;如果在同一个包中,可直接调用,如果在不同的包中,需要导入对应的包
package com.example.kotlindemo.basic
// 顶层函数
fun top() {
println("顶层函数")
}
2. 局部函数
一个函数在另一个函数内部,内部函数可以调用外部函数
// 局部函数
fun part(name: String) {
val test: Int = 0
fun segment(name: String) {
println("可以访问局部变量:${test}")
}
}
3. 递归函数&尾递归函数
1) 递归函数: 递归函数指的是在函数体内部调用函数本身
// 递归函数
fun sum(num : Int) : Int {
return if (num == 1) {
num
} else {
num+sum(num-1)
}
}
2) 尾递归函数: 如果一个函数中所有递归调用都出现在函数的末尾,我们称这个递归函数是尾递归函数。<u>通常情况下,尾递归函数一般用在连续求和、连续求差等程序中。</u>
// 尾递归函数
fun tailSum(num : Int,total : Int = 0) : Int {
return if (num == 1) {
1 + total
} else {
tailSum(num - 1,num+total)
}
}
3)尾递归函数优化:Kotlin中提供了一个tailrec修饰符来修饰尾递归函数,此时编译器会优化该尾递归函数,将尾递归函数转化为while循环,程序会快速高效地运行,并且无堆栈溢出的风险。
// 尾递归函数优化
tailrec fun tailRecSum(num: Int, total: Int = 0): Int {
return if (num == 1) {
1 + total
} else {
tailRecSum(num - 1, num + total)
}
}
调用结果
fun main() {
println("递归函数:${sum(4)}")
// 直接报错:StackOverflowError
println("尾递归函数:${tailSum(100000)}")
// 结果:705082704
println("尾递归函数优化:${tailRecSum(100000)}")
}
4. 中缀函数
-
概念:标有 infix 关键字的函数也可以使⽤中缀表示法(忽略该调⽤的点与圆括号)调⽤。是DSL语法应用中不可或缺的一部分,后面再讲。
-
满足条件:
- 它们必须是成员函数或扩展函数。
- 它们必须只有一个参数。
- 其参数不得接受可变数量的参数且不能有默认值。
-
优先级:
- 中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符。
- 中缀函数调用的优先级高于布尔操作符 && 与 || 、 is- 与 in- 检测以及其他一些操作符
中缀函数总是要求指定接收者与参数
class InfixTest {
private infix fun test(str : String ) = println(str)
fun build() {
test("adb")
this test "adb"
}
}
书籍:《Kotlin从基础到实战》、Kotlin官方文档