Kotlin_3_函数基础

330 阅读1分钟

函数的基本概念

函数又称为方法,是具有特定功能的一段独立程序。函数可以将功能代码进行封装,在使用时直接调用即可,这样程序代码不仅看起来简洁,而且还减少了代码量。

函数的语法格式

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)
}
  • returnreturn语句返回的值,该值会返回给调用者。

* 一个语法糖:当函数中只有一行代码时...

可以不写函数体,直接将函数代码写在函数定义的尾部,以=连接。同时,还可以省略返回值类型。其中,=实际相当于一个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