Kotlin开发笔记:使用函数
创建函数
Kotlin中的函数以fun关键字为前缀,然后紧跟函数名,参数列表,返回值类型,函数体。
参数列表可以为空,若无返回值或者函数体是一个表达式,那个返回值类型也可以省略。
KISS原则
Kotlin遵循KISS(Keep it Simple, Stupid)原则。即函数要尽可能的简单,不混乱没有小错误。
下面是一个最短的函数之一:
fun greet() = "Hello"
println(greet())
三种函数体
-
1.表达式函数。即函数体就是一个表达式并用等号连接。比如:
fun sayHello() = println("Well , Hello")
如果是一个表达式函数,那么系统可以推断返回值类型,那么就可以省略返回值类型。需要说明的是,return关键字不允许用于没有块体的函数,比如上面的表达式函数就是没有块体的函数。
-
2.块体函数。就是我们原来在Java中写的函数形式一样,函数体用一个花括号包裹。比如:
fun sayHello(content:String):Unit{ println("Welcome: $content") return Unit }
唯一的不同点可能就是返回值类型写在最后
-
3.Lambda表达式函数。即函数返回一个Lambda表达式,该函数的函数体用上面两种函数的结合连接,即用={函数体}的形式连接。该类函数可能不太实用因为Lambda表达式函数的使用和一般函数的使用不太一样,一般我们不会用这类函数。比如:
fun maxLambda(number1:Int,number2: Int)= { if(number1 > number2) number1 else number2 }
但是我们在调用的时候得这样调用:
println(maxLambda(num1,num2)()) 或者 println(maxLambda(num1,num2).invoke())
这是因为Kotlin对于Lambda表达式的函数的实现底层会自动创建一个类(Function类),所以相当于Lambda表达式函数返回了一个实体类,你要调用这个方法的话所以就需要执行invoke()方法
函数的参数列表
默认参数
如果你的函数有两个需要的参数,但是想要传入一个参数时也让它工作就可以使用默认参数。它会为你缺省的参数提供一个默认的值:
fun welcome(name:String,content:String = "Hello"){
println("$name,$content")
}
这样,在你只传入一个name参数时,函数也能正常工作,content的值被设定为了默认的"Hello"。添加默认参数的方法也很简单,和上面所做的一样,在参数后面跟一个 = 并且指定它的默认值即可。
**需要注意的是,一般我们的默认参数都需要在参数列表的常规参数之后,**若不遵循,会出现以下后果:
-
由于常规参数需要一个值,所以它会强迫你为默认参数提供一个值,这就违背了使用默认参数的初衷。
-
如果调用方使用命名参数,则可以跳过默认参数。
-
具有默认参数的参数可以放在表示lambda表达式的最后一个参数之前。
命名参数
在我们调用函数的时候,可能经常会出现你不知道传入的每一个参数代表什么的时候,比如说:
createPerson("Scott",12,152,43)
也许我们可以根据函数名推断出第一个参数"Scott"为创造出来的人的姓名,但是之后的三个参数我们一时半会可能并不能知道它们的意义,只有在查看了文档后我们才能知道每个参数的含义。现在让我们改变一下函数的调用:
createPerson(name = "Scott", age = 12, weight = 43, height = 152)
这样每个参数的含义是不是一目了然了,这就是命名参数的作用之一。而且命名参数的顺序可以是任意的:
createPerson( age = 12,name = "Scott",height = 152, weight = 43)
当然我们还可以混合使用命名参数,但是命名参数必须在位置参数之后 :
createPerson("Jack",12,weight = 43, height = 152)
可变参数列表
在Java中我们也接触过可变参,可变参的处理是按照数组的方式处理的,在Kotlin中也类似。Kotlin中可变参用关键字vararg修饰,比如:
fun selectOu(vararg numbers:Int):ArrayList<Int>{
val ans = ArrayList<Int>()
for(number in numbers){
if(number % 2 == 0)
ans.add(number)
}
return ans
}
按照Java中的方式处理即可
这里有几个建议:
- 1.vararg参数放在参数列表的末尾,不然调用方就会被强制使用命名参数
- 2.如果最后一个参数是Lambda表达式,则将其放在Lambda表达式之前
spread运算符
spread运算符是用来将数组或者列表中的值传递给可变参vararg的,具体来说就像这样,我们运用之前写的代码:
val arrs = intArrayOf(1,2,3,4,5,9,10,20,22,63,73,83,100)
val arrs2 = listOf(1,2,3,4,5,9,10,20,22,63,73,83,100)
val answer = selectOu(*arrs2.toIntArray())
val answer2 = selectOu(*arrs)
需要注意的是spread运算符只能用在数组上,如果想把列表啥的传进去,就需要先把列表转化为数组,然后在对数组使用spread运算符,就和上面一样:
val arrs2 = listOf(1,2,3,4,5,9,10,20,22,63,73,83,100)
val answer = selectOu(*arrs2.toIntArray())
解构
结构化或构造是从不同的变量中创建对象,而解构相反,是从对象中提取出需要的值。我们以一个三元组为例,传统的做法:
fun destructTest(){
val result = getFullName()
val first = result.first
val second = result.second
val third = result.third
println("first=$first,second=$second,third=$third")
}
而解构的做法:
fun destructTest2(){
val result = getFullName()
val(first,second,third) = result
println("first=$first,second=$second,third=$third")
}
如果想要跳过一些元素,可以用下划线跳过:
val(first,_,third) = result
如果你想要跳过其他的值而只要一个一个值可以用下划线一次跳过多个,比如:
val(_,third) = result
这样就只获得了third的值