函数的基本概念
函数又称为方法,是具有特定功能的一段独立程序。函数可以将功能代码进行封装,在使用时直接调用即可,这样程序代码不仅看起来简洁,而且还减少了代码量。
函数的语法格式
fun main(args:Array<String>):Unit{}
args函数参数名,可以随便起。是一个变量,用于接收调用函数时传入的数据。Array<String>字符串数组。用于限定调用函数时传入参数的数据类型。Unit代表无类型,可省略。也可以按需要写String Int Double等等。
通过调用math包,写一个比较大小的函数:
import kotlin.math.max
fun largerNumber(num1:Int, num2:Int):Int {
return max(num1,num2)
}
return被return语句返回的值,该值会返回给调用者。
* 一个语法糖:当函数中只有一行代码时...
可以不写函数体,直接将函数代码写在函数定义的尾部,以=连接。同时,还可以省略返回值类型。其中,=实际相当于一个return。
因此,上面比较大小的函数就可以简写为:
import kotlin.math.max
fun largerNumber(num1:Int, num2:Int) = max(num1, num2)
函数的4种类型(Useless)
-
无参无返回值函数
fun aloneFun() { println('Hello World') } -
无参有返回值函数
fun aloneFun() { return "Alone,alone and ALONE" } -
有参无返回值函数
fun justHelloPrint(s:String) { println("Hello $s") } -
有参有返回值函数
fun backToStr(s:String) { return s }
函数的参数
具名参数
fun info(name:String,age:Int) {
println("Name: $name")
println("Age: $age")
}
fun main() {
info("Zhang", 26)
// info(name="Zhang",age=26)
}
默认参数
fun info(name:String="Zhang",age:Int=26) {}
可变参数 vararg
可变参数,是指参数类型确定但个数不确定的参数,可变参数通过vararg关键字标识,我们可以将其理解为数组。可变参数通常声明在形参列表中的最后位置,如果不声明在最后位置,那么可变参数后面的其他参数都需要通过命名参数的形式进行传递。
fun scoreList(name:String,vararg scores:Int) {
var result = 0
scores.forEach() {
result += it
}
println("$name's Score is $result")
}
fun main() {
scoreList("Zhang", 100,80,89,93,95)
}
如果,想在函数中直接传递进去一个数组,则需要*前缀操作符,如下:
fun scoreList(name:String,vararg scores:Int) {
var result = 0
scores.forEach() {
result += it
}
println("$name's Score is $result")
}
fun main() {
var score = intArrayOf(100,80,89,93,93) //IntArray
scoreList("Zhang", *score) //inferred type is Array<Int> but IntArray was expected
}
完成一个小任务,做一个加法计算器add,要求可以传入一个数组,返回相加之和:
fun add(vararg nums:Int):Int {
var result = 0
nums.forEach() {
result += it
}
return result
}
fun main() {
println(add(1,2,3,4))
}
函数的分类
顶层函数(目前还没有理解)
顶层函数又称为包级别函数,可以直接放在某一个包中,而不像Java一样必须将函数放在某一个类中。在Kotlin中,函数可以独立存在,之前写过的很多函数都是顶层函数,例如经常用的
main()函数。顶层函数在被调用时,如果在同一个包中,可直接调用,如果在不同的包中,需要导入对应的包。
成员函数
成员函数是在类或对象内部定义的函数,其语法格式如下:
class ClassName {
fun funName() {
...
}
}
class是定义类的一个关键字。
class Person {
fun hello() {
println("Hello.")
}
}
fun main() {
// var person:Person = Person()
// person.hello()
Person().hello()
}
局部函数(嵌套函数)
fun funName() {
fun funName(){
...
}
...
}
A BORING example:
fun total(a:Int) {
val b:Int = 5
fun add():Int {
return a+b
}
println(add())
}
fun main() {
total(3)
}
递归函数
递归函数指的是在函数体内部调用函数本身。递归函数可以用少量的代码实现需要多次重复计算的程序。
// 使用递归函数求1..100的和
fun sum(num:Int):Int {
if (num==1) {
return 1
}else {
return num + sum(num-1)
}
}
fun main() {
println(sum(5))
}
尾递归函数(目前还没有整明白)
如果一个函数中所有递归调用都出现在函数的末尾,我们称这个递归函数是尾递归函数。尾递归函数的特点是在递归过程中不用做任何操作,当编译器检测到一个函数调用是尾递归函数时,它就覆盖当前的活动记录而不是在栈中去创建一个新的。因为递归调用是当前活跃期内最后一条待执行语句,于是当调用返回时栈中没有其他事情可做,因此也就没有保存的必要。这样可以大大缩减所使用的栈空间,使得程序运行效率变得更高。虽然编译器能够优化尾递归造成的栈溢出问题,但是在编程中还是应该尽量避免尾递归的使用。
尾递归函数是一种特殊的递归函数,特殊之处在于该函数的调用出现在函数的末尾。
将上面的函数改为尾递归函数:
// 使用递归函数求1..100的和
fun sum(num:Int,total:Int=0):Int {
if (num==1) {
return 1+total
}else {
return sum(num-1,num+total)
}
}
fun main() {
println(sum(100)) // 5050
}
tailrec:尾递归函数的优化
在Kotlin中,尾递归函数一般会循环调用,当调用次数过多时,程序会出现栈溢出的问题,为了解决这个问题,Kotlin中提供了一个
tailrec修饰符来修饰尾递归函数,此时编译器会优化该尾递归函数,将尾递归函数转化为while循环,程序会快速高效地运行,并且无堆栈溢出的风险。
上面的sum()函数如果传递参数为100000,则程序在运行时会出现内存溢出的问题,可以使用tailrec修饰符来修饰尾递归函数,避免因循环次数过多而造成的内存溢出。
tailrec fun sum(num:Int,total:Int=0):Int {
if (num==1) {
return 1+total
}else {
return sum(num-1,num+total)
}
}
fun main() {
println(sum(100000)) // 705082704
}
函数的重载
假如存在三个同名函数,但它们需要的参数类型、个数都不相同(不必管return的结果是否一致),Kotlin会根据传递的不同参数自动匹配,来确定调用的时哪个重载函数。这叫做函数的重载。
我们先定义三个函数:
fun totalNum(num:Int):Int {
if (num==1) {
return 1
}else {
return num+totalNum(num-1)
}
}
fun totalNum(num:Float):Float {
if (num==1f) {
return 1f
}else {
return num+totalNum(num-1)
}
}
fun totalNum(num:Int,sum:Int=0):Int {
if (num==1) {
return 1+sum
}else {
return totalNum(num-1,num+sum)
}
}
然后分别调用三个函数:
fun main() {
val a1 = totalNum(5)
val a2 = totalNum(5f)
val a3 = totalNum(5,0)
print("a1:$a1\na2:$a2\na3:$a3\n")
}
// a1:15
// a2:15.0
// a3:15