1. 程式人生 > >函式的定義與呼叫

函式的定義與呼叫

1、在kotlin中建立集合


kotlin沒有自己專門的集合類,而是採用的java的集合類,不過書寫方式不一樣。

val set=hashSetOf(1,7,53) //對應hashset
val list=arrayListOf(1,7,53)   //ArrayList
val map=hashMapOf(1 to "one",7 to "seven",53 to "fifty-three")//HashMap

不過kotlin有自己新增的方法:last(),max()集合中最後一個元素和最大的元素。

2、讓函式更好呼叫


java的集合都有一個預設的toString()實現,但是它的輸出格式是固定的。

val list=listOf(1,2,3)//listOf對應的是(Arrays內部類ArrayList)
println(list)
結果:[1,2,3]

上面的結果是固定格式的,預設實現了toString().

fun <T> joinToString(collection:Collection<T>,separator:String,prefix:String,postfix:String):String{
    val result=StringBuilder(prefix)
    for((index,element) in collection.withIndex()){
    if(index>0) result.append(separator)
    result.append(element)
    }
    result.append(postfix)
    return result.toString()
}
val list=listOf(1,2,3)
println(joinToString(list,"; ","(",")"))
結果:(1;2;3)

當我們想要改變集合輸出格式的時候可以自定義,像上面這樣:逗號變分號。

2.1 命名引數

在上面的例子中,我們單看這一句joinToString(list,"; ","(",")")會發現我們必須要找到上面對應的函式宣告才能更好的理解我們寫的是啥。
為了解決這個問題,kotlin引出了命名引數:當呼叫一個kotlin自定義的函式時,可以顯式地標明一些引數的名稱。

joinToString(list,separator=";",prefix="(",postfix=")")

2.2 預設引數值

在宣告函式的時候,指定引數的預設值,可以避免建立過載的函式。

fun <T> joinToString(collection:Collection<T>,separator:String,prefix:String,postfix:String):String

當你呼叫的時候可以用所有引數來呼叫這個函式,也可以省略掉部分引數。

3、擴充套件函式和屬性


Kotlin 可以對一個類的屬性和方法進行擴充套件,且不需要繼承或使用 Decorator 模式。
擴充套件是一種靜態行為,對被擴充套件的類程式碼本身不會造成任何影響。

3.1 匯入和擴充套件函式

擴充套件函式可以在已有類中新增新的方法,不會對原類做修改.
擴充套件函式定義形式:

fun receiverType.functionName(params){
    body
}
  • receiverType:表示函式的接收者,也就是函式擴充套件的物件
  • functionName:擴充套件函式的名稱
  • params:擴充套件函式的引數,可以為NULL
    以下例項擴充套件 User 類 :
class User(var name:String)

/**擴充套件函式**/
fun User.Print(){
    print("使用者名稱 $name")
}

fun main(arg:Array<String>){
    var user = User("Runoob")
    user.Print()
}
例項執行輸出結果為:
使用者名稱 Runoob

下面程式碼為 MutableList 新增一個swap 函式:

// 擴充套件函式 swap,調換不同位置的值
fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1]     //  this 對應該列表
    this[index1] = this[index2]
    this[index2] = tmp
}

fun main(args: Array<String>) {

    val l = mutableListOf(1, 2, 3)
    // 位置 0 和 2 的值做了互換
    l.swap(0, 2) // 'swap()' 函式內的 'this' 將指向 'l' 的值

    println(l.toString())
}
例項執行輸出結果為:
[3, 2, 1]

3.2 不可重寫的擴充套件函式

擴充套件函式是靜態解析的,並不是接收者型別的虛擬成員,在呼叫擴充套件函式時,具體被呼叫的的是哪一個函式,由呼叫函式的的物件表示式來決定的,而不是動態的型別決定的:

open class C

class D: C()

fun C.foo() = "c"   // 擴充套件函式 foo

fun D.foo() = "d"   // 擴充套件函式 foo

fun printFoo(c: C) {
    println(c.foo())  // 型別是 C 類
}

fun main(arg:Array<String>){
    printFoo(D())
}
例項執行輸出結果為:
c

若擴充套件函式和成員函式一致,則使用該函式時,會優先使用成員函式。

class C {
    fun foo() { println("成員函式") }
}

fun C.foo() { println("擴充套件函式") }

fun main(arg:Array<String>){
    var c = C()
    c.foo()
}
例項執行輸出結果為:
成員函式

3.3 擴充套件屬性

除了函式,Kotlin 也支援屬性對屬性進行擴充套件:

val <T> List<T>.lastIndex: Int
    get() = size - 1

擴充套件屬性允許定義在類或者kotlin檔案中,不允許定義在函式中。初始化屬性因為屬性沒有後端欄位(backing field),所以不允許被初始化,只能由顯式提供的 getter/setter 定義。

val Foo.bar = 1 // 錯誤:擴充套件屬性不能有初始化器

擴充套件屬性只能被宣告為 val。

4、可變引數、中綴呼叫和庫的支援


4.1 擴充套件java集合的API

fun <T> List<T>.last():T//返回最後一個元素
fun Collection<Int>.max():Int//返回集合中的最大值

為什麼kotlin用的是java的集合,卻能給它新增自己又增加的方法?
函式last和max都被宣告成了擴充套件函式。

4.2 可變引數:讓函式支援任意數量的引數

可變引數的關鍵字vararg,可以用來宣告一個函式將可能有任意數量的引數
fun listOf(vararg values:T):List{...}
kotlin庫中是這樣定義listOf()函式的,正因為這樣我們呼叫它時才可以傳遞任意個數的引數給它
kotlin和java的另一個區別是:當需要傳遞的引數已經包裝在陣列中時,呼叫該函式的語法。
在java中可以按原樣傳遞陣列,kotlin要求你顯式地解包陣列。這個叫做展開運算子,在引數前面加*

fun main(args:Array<String>){
    val list=listOf("args: ",*args)
    println(list)
}

4.3 鍵值對的處理:中綴呼叫和重構宣告

val map=mapOf(1 to "one",7 to "seven",53 to "fifty-three")

這行程式碼中的單詞to不是內建結構,而是一種特殊的函式呼叫,被稱為中綴呼叫。

重構宣告:
中綴呼叫可以與只有一個引數的函式一起使用,無論是普通的函式還是擴充套件函式。要允許使用中綴符合呼叫函式,需要使用infix修飾符來標記它。

infix fun Any.to(other:Any)=Pair(this,other)

我們可以直接用Pair的內容來初始化兩個變數。
val (number,name)=1 to "one"
這個功能稱為解構宣告。

5、字串和正則表示式的處理


5.1 分割字串

println("12.345-6.A".split("\\.|-".toRegex()))
結果:[12,345,6,A]

kotlin提供了一些名為split的,具有不同引數的過載的擴充套件函式。用來承載正則表示式的值需要一個Regex型別,而不是String。上面例子中就是使用擴充套件函式toRegex將字串轉換為正則表示式。
但是對於一些簡單的情況,不需要使用正則表示式。kotlin中的split擴充套件函式的其他過載支援任意數量的純文字字串分隔符:

println("12.345-6.A".split(".","-"))
[12,345,6,A]

5.2 正則表示式和三重引號的字串

我們解析一個檔案路徑:/Users/yole/kolin-book/chapter.doc
①使用String的擴充套件函式來解析檔案路徑

fun parsePath(path:String){
    val directory=path.substringBeforeLast("/")
    val fullName=path.substringAfterLast("/")
    val fileName=fullName.subStringBeforeLast(".")
    val extension=fullName.subStringAfterLast(".")
    println("Dir:$directory,name:$fileName,ext:$extension")
}
parsePath("/Users/yole/kolin-book/chapter.doc")
結果:Dir:Users/yole/kolin-book,name:chapter,ext:doc

②使用正則表示式來解析檔案路徑

fun parsePath(path:String){
    val regex="""(.+)/(.+)\.(.+)""".toRegex()
    val matchResult=regex.matchEntire(path)
    if(matchResult!=null){
        val (directory,filename,extension)=matchResult.destructured
        println("Dir:$directory,name:$fileName,ext:$extension")
    }
}

三重引號字串不需要對任何字元進行轉義。第一個(.+)包含最後一個斜線前的字串。第二個包含最後一個點前的字串,第三個包含剩餘部分。

5.3 多行三重引號的字串

三重引號字串不僅可以避免轉義字元,而且它可以包含任意字元,包括換行符。而且它提供了一種簡單的方法把包含換行符的文字嵌入到程式中。

val kotlinLogo="""| //
                 .|//
                 .|/ \"""
println(kotlinLogo.trimMargin("."))
結果: | //
      |//
      |/ \