kotlin的函数基础比较简单,这里很简要的说明一下。
函数声明
这个函数声明就随意示范一下吧:
函数的声明:fun 方法名 (形参列表):返回值类型 { 方法体}
fun double(x: Int): Int {
return 2*x
}
函数用法:
fun main(args: Array<String>) {
var sum = sum(1, 6)
println(sum)
}
代码调用了上面声明的函数
参数
Kotlin函数参数使⽤ Pascal 表⽰法定义,即 name: type。参数⽤逗号隔开。每个参数必须有显式类型。
fun powerOf(number: Int, exponent: Int) {
……
}
默认参数
函数参数可以有默认值,当省略相应的参数时使⽤默认值。与其他语⾔相⽐,这可以减少重载数量。
默认值通过类型后⾯的 = 及给出的值来定义。
fun add(a : Int = 0, b : Int = 0) = a + b
覆盖⽅法总是使⽤与基类型⽅法相同的默认参数值。当覆盖⼀个带有默认参数值的⽅法时,必须从签名中省略默认参数
open class B<T>{
open fun read(array : Array<T>, off : Int = 0, len : Int = array.size ){
for (a in array){
println(a)
}
}
}
class C<E> : B<E>() {
override fun read(array: Array<E>, off: Int, len: Int) {
for (a in array){
println("$a + ")
}
}
}
fun main(args: Array<String>) {
C<Int>().read(arrayOf(3, 4, 6, 76, 91, 67))
}
如果⼀个默认参数在⼀个无默认值的参数之前,那么该默认值只能通过使⽤命名参数调⽤该函数来使用
fun add(a:Int = 1,b:Int):Int{ //参数b之前有默认参数
return a+b
}
fun main(args: Array<String>) {
println(add(2,2)) //这样调用没有问题
//但是如果我想使用a的默认值那么就要使用命名参数
println(add(b=2))
}
不过如果最后⼀个 lambda 表达式参数从括号外传给函数函数调用,那么允许默认参数不传值
fun add(a: Int = 1,b: Int = 2,show:(result:Int) -> Unit){
show(a+b)
}
fun main(args: Array<String>) {
add(2){result -> println(result)} //这个时候是a被赋予值,b使用默认值
add { result -> println(result)} //这个时候是都是用的是默认值
}
命名参数,这是在函数调用的时候,明确调用参数,从而提高程序的可读性, 有时候我们设定默认值的时候可能可读性很差。
fun <T> readArray(array : Array<T>, off : Int = 0,len : Int = array.size){
if (off >= 0 && len <= array.size && len >= 0 && len + off <= array.size){
for (i in off ..(len + off - 1)){
println(array[i])
}
}
}
//这样我我们调用者就知道函数的含义了
fun main(args: Array<String>) {
readArray(arrayOf(13,3,45,67,98,32,43),off = 2, len =4)
}
返回值为Unit的函数
如果⼀个函数不返回任何有⽤的值,它的返回类型是 Unit 。Unit 是⼀种只有⼀个值⸺ Unit 的类型。这个值不需要显式返回
fun sayHello(name :String?):Unit{
if (name != null){
println("hello $name")
}else{
println("hello")
}
//return Unit or return可选
}
//上面的相当于下面的函数
fun sayHello(name :String?){
if (name != null){
println("hello $name")
}else{
println("hello")
}
}
单表达式的函数
当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可(这个很方便,大大简化了代码的编写)
下面的代码我们没有设置返回值的类型,因为表达式能推断出来。
fun add(a : Int, b : Int) = a + b
注意:具有块代码体的函数必须始终显式指定返回类型,除非他们旨在返回 Unit ,在这种情况下它是可选的。Kotlin 不推断具有块代码体的函数的返回类型,因为这样的函数在代码体中可能有复杂的控制流,并且返回类型对于读者(有时甚⾄对于编译器)是不明显的。
可变函数参数
函数的参数(通常是最后⼀个)可以用 vararg 修饰符标记
fun <T> asList(vararg items : T):List<T>{
var list = ArrayList<T>()
for (i in items){
list.add(i)
}
return list
}
fun main(args: Array<String>) {
var list = asList("hello","hi","love")
println(list)
//另外还可以延伸的传入参数,如吧一个数组传入,前面使用*号,这里叫做伸展操作符
var array = arrayOf("tom","jian","nihao")
var list1 = asList("1",*array)
println(list1)
}
在函数内部,类型 T 的 vararg 参数的可见方式是作为 T 数组,即上例中的 ts 变量具有类型 Array 。只有⼀个参数可以标注为 vararg 。如果 vararg 参数不是列表中的最后⼀个参数,可以使⽤命名参数语法传递其后的参数的值,或者,如果参数具有函数类型,则通过在括号外部传⼀个 lambda。
当我们调⽤ vararg -函数时,我们可以⼀个接⼀个地传参,例如 asList(1, 2, 3) ,或者,如果我们已经有⼀个数组并希望将其内容传给该函数,我们使⽤伸展(spread)操作符(在数组前⾯加 * )(代码如上):
函数的中缀表示法
使用中缀表示法的三个条件 1.他们是成员函数或者是扩展函数 2.他们只有一个参数 3 他们使用infix标注
infix fun Int.add1(b : Int):Int{
return this + b
}
fun main(args: Array<String>) {
var a = 1
var b = 2
var c = 1.add1(3) //调用中缀表示法的函数调用,或者 a add b 的调用形式也可以
println(c)
}
函数作用域
局部函数
Kotlin ⽀持局部函数,即⼀个函数在另⼀个函数内部
fun outer(){
var a = 1
var b = 4
fun add(a: Int,b: Int):Int{
return a + b
}
println(add(a , b))
}
fun main(args: Array<String>) {
outer()
}
fun outer(){
var a = 1
var b = 4
fun add():Int{
return a + b //局部函数可以访问外部函数的局部变量
}
println(add())
}
fun main(args: Array<String>) {
outer()
}
关于成员函数(定义在类中),和泛型函数,其他章都有提到过,所以这里省略掉。
尾递归函数
Kotlin ⽀持⼀种称为尾递归的函数式编程风格。这允许⼀些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险。当⼀个函数用tailrec 修饰符标记并满足所需的形式时,编译器会优化该递归,留下⼀个快速而高效的基于循环的版本。
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
//这段代码计算余弦的不动点(fixpoint of cosine),这是⼀个数学常数。它只是重复地从 1.0 开始调⽤ Math.cos,直到结果不再改变,产⽣
//0.7390851332151607的结果
//要符合 tailrec 修饰符的条件的话,函数必须将其⾃⾝调⽤作为它执⾏的最后⼀个操作。在递归调⽤后有更多代码时,不能使⽤尾递归,并且不能⽤在
//try/catch/finally 块中。⽬前尾部递归只在 JVM 后端中⽀持。
fun main(args: Array<String>) {
var x = findFixPoint(Math.PI/2)
println(x)
}