kotlin 函數詳解
構造方法
在Kotlin中,一個類可以有一個primary構造方法以及一個或多個Secondary構造方法,primary構造方法是類頭(class header)的一部分,它位於類名後面,可以擁有若干參數,如果primary構造方法沒有任何註解或是可見性關鍵字修飾,那麼construction關鍵字可省略。
class Myclass constructor(user: String) {
private val name: String = user.toLowerCase()
init {
println(user)
}
}
fun main(args: Array<String>) {
val myClass = Myclass("zhangsan")
}
次構造方法
class Person constructor(username: String) {
private var username: String
private var age: Int
private var sex: String
init {
this.age = 20
this.sex = "男"
this.username = "張三"
}
constructor(username: String, age: Int) : this(username) { //次構造方法,this傳遞主構造方法
this.username = username
this.age = age
this.sex = "女"
}
constructor(username: String, age: Int, sex: String) : this(username, age) {
this.username = username
this.age = age
this.sex = sex
}
fun printInfo() {
println("username:${this.username},age:${this.age},sex:${this.sex}")
}
}
fun main(args: Array<String>) {
val person = Person("李四")
val person2 = Person("李四", 70)
val person3 = Person("李四", 20, "男")
println(person.printInfo())
println(person2.printInfo())
println(person3.printInfo())
}
var,val 在構造方法中定義參數:
class Student(private val name: String,private val age: Int) {
//加了var val就是成員變量,刪掉就會報錯,數據類中都的參數會加上var或者val
fun printInfo() {
println("name:$name,age:$age")
}
}
如果構造方法擁有註解或是可見修飾符,那麼constructor關鍵字是不能省略的,並且位於修飾符後面
class Student2 private constructor(username: String) {}
默認參數(default arguments)
在jvm上,如果類的primary構造方法的所有參數都擁有默認值,那麼kotlin編譯器就會成爲這個類生成,一個不帶參數的構造方法,這個不帶參數的構造方法會使用這些參數的默認值,這樣做的目的在於可以跟Spring等框架更好的集成
class Student3(val username: String = "zhangsan") {}
fun main() {
val student = Student3()//沒有傳遞任何參數,默認參數就是無參構造函數
println(student.username) //zhangsan
}
fun test(a:Int=0,b:Int=2)= println(a-b)
fun main(args: Array<String>) {
test(2) //a=2,默認傳遞第一個參數
test(b=3)//b=3,具名參數,具體賦值給哪一個參數
test(2,3)
}
對於重寫的方法來說,子類所擁有的重寫方法會使用與父類相同的默認參數值。在重寫一個擁有默認參數值的方法時,方法簽名中必須要將默認參數值省略掉。如下例子:
open class A{
open fun method (a:Int,b:Int=3)=a+b
}
class B:A(){
override fun method(a: Int, b: Int=5)=a+b //會報錯。當前b的值是3,不能去指定默認值
override fun method(a: Int, b: Int)=a+b //正確
}
fun main(args: Array<String>) {
println(A().method(1)) //6
println(B().method(6)) //11
}
如果一個默認參數位於其他無默認值的參數前面,那麼默認值只能通過在調用函數時使用具名函數的方式來使用,如下例子:
fun test2(a:Int =1,b:Int)= println(a-b)
fun main(args: Array<String>) {
test2(b=3)//具名參數
test2(3)// 此時傳給的a=3,會報錯,因爲當前a=1了。
}
lamba 表達式的函數
如果函數的最後一個參數是lambda表達式,而且在調用時是位於圓括號之外。那麼就可以不指定lambda表達式的具名參數名。如下例子:
fun test3(a: Int=1,b: Int=2,compute:(x:Int,y:Int)->Unit){
compute(a,b)
}
fun main(args: Array<String>) {
test3(2,3, {a,b -> println(a-b)}) //-1
test3(2,3) {a,b -> println(a-b)} //-1
test3(2){a,b -> println(a-b)} //0
test3{a,b -> println(a-b)} //0
//以上表示都正確的
}
具名參數
在調用函數時,函數參數可以是具名的。當一個函數有大量參數或是一些參數擁有默認值,這種調用方式是比較方便的。如下例子:
fun test4(a: Int,b: Int=2,c: Int=1,d: Int)= println(a+b+c+d)
fun main(args: Array<String>) {
test4(a=2,d = 5)
test4(1,2,3,4)
}
可變參數 vararg
一個方法中,只允許一個參數爲vararg,通常作爲最後一個參數,如果vararg不是最後一個參數,那麼其後的參數就需要通過具名參數形式進行傳遞;如果其後的參數是函數類型,那麼還可以通過在圓括號外傳遞lambda表達式來實現。如下例子:
fun test5(vararg strings:String){
println(strings.javaClass) //strings 的java類型是數組類型
strings.forEach { println(it) }
}
fun main(args: Array<String>) {
test5("a","sf","sdf")
test5(strings = arrayOf("a","c","f")) //此處是錯誤的
//要加一個*號,分散運算符
test5(strings = *arrayOf("a","c","f"))
val arrays= arrayOf("a","b")
test5(*arrays)
}
內聯函數(inline function)
inline fun myCalculate(a:Int,b:Int)=a+b
fun main(args: Array<String>) {
println(myCalculate(1,2))
}
匿名函數 必須要放在圓括號裏面實現
fun(x: Int, y: Int) = x + y //complier error必須要有一個方法名
fun main(args: Array<String>) {
fun(x: Int, y: Int) = x + y
fun(x: Int, y: Int): Int {
return x + y
}
val strings = arrayOf("hello", "world")
strings.filter(fun(item): Boolean = item.length > 3).forEach(fun(item) {
println(item)
})
}
注意:
- 在調用函數時,如果同時使用了位置參數與具名參數,那麼所有的位置參數都必須要位於第一個具名參數之前。比如說,foo(1,x=2)是允許的,foo(x=2,1)是不允許的。
- 在kotlin中調用java方法時不能使用具名參數語法,因爲java字節碼並不總是會保留方法參數名信息。