Kotlin基礎(chǔ)語法教程(一)

Kotlin概述

Kotlin是由開發(fā)過IntelliJ IDEA、Android Studio旧蛾、PyCharm等IDE的著名IDE廠商JetBrains公司設(shè)計并開源的編程語言。2011年7月推出的Kotlin項目深受《Effective Java》的影響褐着,直到2016年2月15日第一個官方穩(wěn)定版本Kotlin v1.0才正式發(fā)布,2017年Google I/O開發(fā)者大會中汗唱,Google宣布Kotlin成為Android開發(fā)的一級語言谷饿,Kotlin “轉(zhuǎn)正”未荒。

Kotlin是一種運(yùn)行在JVM上的靜態(tài)類型編程語言,可以編譯為Java字節(jié)碼接箫,同時也可以編譯成JavaScript攒读、本地(Native)代碼,方便在沒有JVM的設(shè)備上運(yùn)行辛友。Kotlin語言具有以下特點(diǎn):

  • 與Java的編譯薄扁、運(yùn)行速度相似
  • 比Java更安全、簡潔
  • 比最成熟的競爭者Scala更簡潔

Kotlin在語法上具有很多下一代編程語言靜態(tài)語言特性:如類型推斷废累、函數(shù)式編程邓梅、多范式支持、可空性表達(dá)邑滨、擴(kuò)展函數(shù)日缨、模式匹配等。

Kotlin與Java具有良好的兼容性掖看,與Java高度可互操作匣距,在同一項目的開發(fā)中可以同時使用兩種語言進(jìn)行編寫(僅限于不同文件中,不能在同一文件中使用兩種語言)哎壳,如Kotlin可以直接調(diào)用Java的代碼毅待,而Java調(diào)用Kotlin需要使用一些注解,但也不是很復(fù)雜归榕。IntelliJ IDEA提供了Java代碼到Kotlin代碼的轉(zhuǎn)換功能尸红,您只需將Java代碼拷貝粘貼到.kt文件中,IDE就會自動將其轉(zhuǎn)換為Kotlin代碼,方便Java學(xué)習(xí)者順利過渡到Kotlin驶乾。

Kotlin支持像Python一樣的REPL環(huán)境邑飒,可以很方便的進(jìn)行代碼測試,對于語言的學(xué)習(xí)十分有幫助级乐,配置環(huán)境變量后只需要在命令行輸入kotlinc疙咸,即可開啟REPL環(huán)境。

REPL.png

這篇文章面向有Java語言基礎(chǔ)的對Kotlin有興趣的讀者风科,內(nèi)容比較基礎(chǔ)撒轮,主要通過兩種語言的對比進(jìn)行說明。

基礎(chǔ)語法

Hello World

創(chuàng)建項目.png

如圖所示贼穆,使用IntelliJ IDEA新建項目時可選擇Java题山,同時在右側(cè)勾選Kotlin/JVM,或者直接新建Kotlin項目故痊。

fun main(args: Array<String>) {
    println("hello world")
}

上述Kotlin代碼的作用就是輸出hello world顶瞳,看起來比Java等語言簡單得多,Kotlin中通過fun關(guān)鍵字聲明一個函數(shù)愕秫,main是函數(shù)名慨菱,在這里是應(yīng)用程序的入口;args是參數(shù)戴甩,這里代表命令行參數(shù)符喝,它的類型是字符串?dāng)?shù)組,需要注意的是Kotlin的變量名通常寫在類型的前面甜孤,中間用冒號分開协饲。

println()是Kotlin中的頂層函數(shù),對應(yīng)Java中的System.out.println()函數(shù)缴川,頂層函數(shù)不屬于任何類茉稠,可以直接拿來用,類似用法的頂層函數(shù)還有print()等把夸。

Kotlin的語句最后的分號不是必須的而线,只有當(dāng)多個語句寫在同一行時,才必須用分號加以區(qū)分扎即。

變量和數(shù)據(jù)類型

常量和變量
var a = 1
const val b = 2

fun main(args: Array<String>) {
    a = 2
    b = 1            //編譯錯誤
    const val c = 3  //編譯錯誤
    c = 1            //編譯錯誤
    val d = 4
    d = 1            //編譯錯誤
    var e: Float = 5.0f
    e = 1
}
//聲明對象,對應(yīng)Java中需要通過構(gòu)造方法私有化實現(xiàn)的單例
object Test {
    const val TEST = 100
}

Kotlin中聲明變量通常使用val/var 變量名: 變量類型 = 表達(dá)式况凉,如上述代碼中的變量e谚鄙,Kotlin語言支持變量類型的自動推斷,通常都不需要顯式的聲明變量類型刁绒。

Kotlin變量分為var(可變變量)和val(只讀變量闷营,也稱不可變變量、運(yùn)行期常量),其中var是可寫的傻盟,在它的生命周期中可以被多次賦值速蕊,如上述代碼中的ae;而val是只讀的娘赴,它是在運(yùn)行時初始化的规哲,但僅能賦值一次,如對d重新賦值會發(fā)生編譯錯誤诽表,只讀變量相當(dāng)于Java中用final修飾的變量(并不完全相同)唉锌。只讀變量的值只能被修改一次,并且不能被覆蓋竿奏,這可以避免變量的值被錯誤的修改袄简。

Kotlin的常量(編譯期常量)用const val聲明,僅能用于頂層常量和對象中的常量聲明泛啸,如上述代碼中的bTest對象中的TEST常量绿语,在函數(shù)中聲明的c則會發(fā)生編譯錯誤,編譯期常量相當(dāng)于Java中用public final static修飾的常量(并不完全相同)候址,Kotlin中的常量只能是String類型或基本數(shù)據(jù)類型吕粹。

基本數(shù)據(jù)類型
Kotlin基本數(shù)據(jù)類型 Java基本數(shù)據(jù)類型 Java包裝類
Int int java.lang.Integer
Long long java.lang.Long
Float float java.lang.Float
Double double java.lang.Double
Short short java.lang.Short
Char char java.lang.Character
Byte byte java.lang.Byte
Boolean boolean java.lang.Boolean

下表展示了Kotlin中的8種基本數(shù)據(jù)類型對應(yīng)的Java基本數(shù)據(jù)類型和Java包裝類:

Kotlin基本數(shù)據(jù)類型 Java基本數(shù)據(jù)類型 Java包裝類
Int int java.lang.Integer
Long long java.lang.Long
Float float java.lang.Float
Double double java.lang.Double
Short short java.lang.Short
Char char java.lang.Character
Byte byte java.lang.Byte
Boolean boolean java.lang.Boolean

與Java不同,Kotlin的字符類型(Char)不屬于數(shù)值類型宗雇,Kotlin中的基本數(shù)據(jù)類型沒有對應(yīng)的包裝類昂芜,編譯器會視具體情況將其編譯為Java基本數(shù)據(jù)類型或者包裝類對象。

    val a = 100L            //定義Long類型的變量a赔蒲,L后綴(不允許使用l)表示Long類型
    val b = 123_456_789L    //通過_可以分割數(shù)字泌神,使其更清晰
    val c = 0B10010         //0b或0B前綴表示二進(jìn)制數(shù)
    val d = 0x1A            //0x或0X前綴表示十六進(jìn)制數(shù)
    val pi = 3.14159        //pi默認(rèn)是Double類型(不允許使用后綴d或D),不是Float類型
    val e = 2.71828f        //f或F后綴表示Float類型

上述代碼演示了Kotlin中數(shù)值類型的字面量舞虱,其中比較特殊的是:

  • Kotlin的小數(shù)默認(rèn)是Double類型欢际,不能加Dd后綴
  • 為了避免小寫字母l和數(shù)字1的混淆,Kotlin不允許使用小寫字母l作為Long類型整數(shù)的后綴矾兜,必須使用大寫字母L
  • 使用_進(jìn)行比較長的數(shù)字的分割時损趋,不強(qiáng)制要求每3位數(shù)字分割一次
非空類型與可空類型

為了避免Java中經(jīng)常出現(xiàn)的空指針異常(NullPointerException),Kotlin的類型默認(rèn)定義為非空椅寺,即不可接收空值(null)浑槽,直接對非空類型變量賦值null會發(fā)生編譯錯誤。當(dāng)我們確認(rèn)需要可空類型時返帕,可以通過在非空類型后面加一問號(?)桐玻,此時的變量可以接收空值,如:

val a: Int = null       //編譯錯誤
val b: Int? = null

非空類型永遠(yuǎn)不可能為null荆萤,而可空類型則存在潛在的空指針風(fēng)險镊靴,Kotlin不允許可空類型對象直接調(diào)用非空類型對象的屬性或函數(shù)铣卡,也不能把可空類型數(shù)據(jù)賦值給非空類型變量或是傳遞給非空類型參數(shù)。為了使可空類型能夠調(diào)用非空類型的方法偏竟,Kotlin提供了以下幾個運(yùn)算符:

  1. 非空斷言運(yùn)算符:!!
  2. 安全調(diào)用運(yùn)算符:?.
  3. 安全轉(zhuǎn)換運(yùn)算符:as?
  4. Elvis運(yùn)算符(空值合并運(yùn)算符): ?:

下面對這幾個運(yùn)算符進(jìn)行介紹:

  • 非空斷言運(yùn)算符!!:非空斷言運(yùn)算符用于斷言一個可空類型變量不為空值煮落,使用這個運(yùn)算符會存在拋出空指針異常(kotlin.KotlinNullPointerException)的風(fēng)險。
fun main(args: Array<String>) {
    var a: String? = "abc"
    println(a!!.length)     //輸出3
    val b: String? = null
    b!!                     //拋出空指針異常
}

上述代碼由于對值為空的變量b進(jìn)行了非空斷言踊谋,運(yùn)行時會拋出空指針異常蝉仇。在最新版的Kotlin中,若已經(jīng)檢查了變量非空褪子,則允許不使用非空斷言運(yùn)算符直接調(diào)用非空類型的屬性和函數(shù)量淌。

  • 安全調(diào)用運(yùn)算符?.:該運(yùn)算符用于對可空類型變量安全的調(diào)用非空類型的屬性或函數(shù),而不會拋出空指針異常嫌褪,當(dāng)對象為空時呀枢,直接返回空值(null),否則進(jìn)行調(diào)用并返回結(jié)果笼痛。
fun main(args: Array<String>) {
    var a: String? = "abc"
    println(a?.length)      //輸出3
    val b: String? = null
    println(b?.length)      //輸出null
}

它等價于以下代碼:

fun main(args: Array<String>) {
    var a: String? = "abc"
    println(a?.length)
    val b: String? = null
    if(b == null)
        println(null)
    else
        println(b!!.length)     //在最新版的Kotlin中此處的!!可以省略
}
  • 安全轉(zhuǎn)換運(yùn)算符as?:在Kotlin中使用asas?進(jìn)行強(qiáng)制類型轉(zhuǎn)換裙秋,這部分內(nèi)容將在面向?qū)ο蟮亩鄳B(tài)部分進(jìn)行說明。

  • Elvis運(yùn)算符?::該運(yùn)算符名稱的由來是?:像“貓王”(美國搖滾歌手)埃爾維斯·普雷斯利(Elvis Presley)的頭型和眼睛缨伊,其作用是空值合并摘刑。該運(yùn)算符是一個二元運(yùn)算符(注意Kotlin不存在條件 ? 邏輯表達(dá)式1 : 邏輯表達(dá)式2這個三元運(yùn)算符),語法是可空類型數(shù)據(jù) ?: 空值合并到的數(shù)據(jù)刻坊,作用是當(dāng)數(shù)據(jù)非空時枷恕,直接返回數(shù)據(jù),而當(dāng)數(shù)據(jù)為空時谭胚,返回合并到的數(shù)據(jù)徐块。利用該運(yùn)算符,可以很容易的把可空類型轉(zhuǎn)換為非空類型灾而。

fun main(args: Array<String>) {
    var a: String? = "abc"
    println(a?.length ?: "字符串為空")      //輸出3
    val b: String? = null
    val c: Int = b?.length ?: -1
    println(c)                            //輸出-1
}

等價于如下代碼:

fun main(args: Array<String>) {
    var a: String? = "abc"
    println(a?.length ?: "字符串為空")
    val b: String? = null
    val c: Int
    print(c)                //編譯錯誤胡控,非空變量初始化前不能取值,請刪掉此行代碼重新運(yùn)行
    if(b == null)
        c = -1
    else
        c = b!!.length      //在最新版的Kotlin中此處的!!可以省略
    println(c)
}

函數(shù)聲明

Kotlin既有獨(dú)立于類的頂層函數(shù)旁趟,也有類方法昼激,為了避免混淆,這里統(tǒng)稱為函數(shù)锡搜。上述main中演示了參數(shù)的定義橙困,下面的代碼中演示了返回值,返回值應(yīng)在函數(shù)的參數(shù)列表括號之后顯式地聲明耕餐。

fun getMax(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

Kotlin的函數(shù)(包括頂層函數(shù)和類函數(shù))可以帶有參數(shù)默認(rèn)值凡傅,而Java中想要實現(xiàn)類似的功能則需要冗長的方法重載或使用builder模式。

fun main(args: Array<String>) {
    printPerson("小明", age = 18)
}

fun printPerson(name: String, sex: Boolean = true, age: Int): Unit {
    println("姓名:" + name)
    println("性別:" + if (sex) "男" else "女")
    println("年齡:" + age)
}

上述代碼中對參數(shù)sex使用了默認(rèn)值true蛾方,在調(diào)用函數(shù)不提供參數(shù)時其值為true像捶,調(diào)用時使用了命名參數(shù)age,采用命名參數(shù)可以增加代碼的可讀性桩砰,參數(shù)順序可以與函數(shù)定義時不一致拓春,建議帶有默認(rèn)值的參數(shù)放在參數(shù)列表的最后面,需要注意的是在調(diào)用函數(shù)時一旦其中一個參數(shù)采用了命名參數(shù)亚隅,其后所有的參數(shù)都必須采用命名參數(shù)形式傳遞硼莽。上述代碼中函數(shù)的返回值類型定義為Unit,相當(dāng)于Java中的void類型煮纵,此處可以省略返回值類型懂鸵。

字符串模板

原始字符串:使用三個雙引號包起來的字符串,原始字符串中的\將不被識別為轉(zhuǎn)義行疏,字符串中可以包含換行匆光,如:

"""hello
word"""

下面的代碼是使用原始字符串輸出三行內(nèi)容,第2酿联、3行都在行首開始终息,這樣的代碼有時看起來對齊的并不自然。

fun main(args: Array<String>) {
    println(getText())
}

fun getText(): String {
    return """Kotlin is created by JetBrains
Kotlin is a Programming Language running on JVM
We can use Kotlin to create Android apps"""
}

可以使用trimMargin()贞让、trimIndent()裁剪函數(shù)來去除前導(dǎo)空格周崭。

fun getText(): String {
    return """        Kotlin is created by JetBrains
        Kotlin is a Programming Language running on JVM
        We can use Kotlin to create Android apps""".trimIndent()
}

String類型的函數(shù)(方法)trimIndent()用于切割每一行開頭相同數(shù)量的空格。

fun getText(): String {
    return """Kotlin is created by JetBrains
        #Kotlin is a Programming language running on JVM
        #We can use Kotlin to create Android apps""".trimMargin("#")
}

trimMargin()函數(shù)用于從字符串中每行的開頭裁剪指定的字符串參數(shù)以及前面的全部空格喳张,如果不提供參數(shù)续镇,則以|作為參數(shù)默認(rèn)值。

Kotlin還支持類似于PHP中的字符串模板销部,利用這一特性摸航,前面提供的函數(shù)可以進(jìn)行如下改寫:

fun printPerson(name: String, sex: Boolean = true, age: Int): Unit {
    println("姓名:$name")
    println("性別:${if (sex) "男" else "女"}")
    println("年齡:$age")
}

在原始字符串和一般的字符串中都允許使用字符串模板,字符串模板能夠簡化字符串拼接的操作柴墩,字符串模板是以$開頭忙厌,其語法為$變量或常量名${表達(dá)式},如果想要在字符串中使用$符號江咳,請用${'$'}\$代替逢净。

流程控制

if語句/表達(dá)式

Kotlin簡化了Java中的一些語句,將其變?yōu)榫哂蟹祷刂档谋磉_(dá)式歼指,主要有if表達(dá)式爹土、when表達(dá)式、try表達(dá)式踩身、表達(dá)式函數(shù)體胀茵,示例代碼如下:

fun main(args: Array<String>) {
    var a = 1
    var b = 2
    //if表達(dá)式,可以自動推斷出max的類型是Int挟阻,不需要顯式聲明
    val max = if(a > b) a else b
    //對可變變量重新賦值
    a = 5
    b = 3
    //調(diào)用下面定義的getMin函數(shù)
    val min = getMin(a, b)
}
//表達(dá)式函數(shù)體琼娘,返回值是執(zhí)行到的語句塊的最后一條語句
fun getMin(a: Int, b: Int) = if(a > b) {
    println("b < a")
    b       //if表達(dá)式的返回值
} else {
    println("a < b")
    a       //if表達(dá)式的返回值
}
when語句/表達(dá)式

Kotlin放棄了C和Java中的switch語句峭弟,采用一個新的when語句/表達(dá)式,相比switch語句脱拼,when語句/表達(dá)式要更加的強(qiáng)大瞒瘸、靈活。

when是一個多分支的結(jié)構(gòu)熄浓,像if一樣情臭,when的每一個分支都可以是一個代碼塊,when表達(dá)式也具有返回值赌蔑,它的值是塊中最后的表達(dá)式的值俯在。可以用任意表達(dá)式(不只是常量)作為分支條件娃惯,也可以把多個分支條件通過逗號放在一起跷乐,還可以用in!in加上一個區(qū)間檢測一個值是否在一個區(qū)間或者集合中、用is!is加上一個類名判斷是否是某個類的實例(Java中對應(yīng)的是instanceof)趾浅,如果所有分支都不滿足劈猿,則會執(zhí)行else分支(可以沒有)。

fun main(args: Array<String>) {

    val score = 98
    val result = when (score) {
        97, 98, 99 -> "接近滿分了"
        in 90..96, 100 -> {
            println("優(yōu)")
            "優(yōu)秀"
        }
        in 60..89 -> "及格"
        in 0..59 -> "不及格"
        else -> {
            println("成績輸入不正確")
            null
        }
    }
}

上述代碼中的..是區(qū)間運(yùn)算符潮孽,如0..59是生成閉區(qū)間[0, 59]內(nèi)的整數(shù)數(shù)列揪荣,每個區(qū)間是一個可迭代的對象,Kotlin還提供了一個半開區(qū)間運(yùn)算符until往史,如0 until 10則是生成半開區(qū)間[0,10)內(nèi)的整數(shù)仗颈,Kotlin核心庫中共提供了3個閉區(qū)間類:IntRangeLongRangeCharRange椎例。

循環(huán)語句

Kotlin具有和C挨决、Java類似的do-while循環(huán)和while循環(huán),這里不再贅述订歪,主要介紹for循環(huán)脖祈。下面演示一個打印乘法口訣表的代碼:

fun main(args: Array<String>) {
    for(i in 1..9) {
        for(j in 1..i)
            print("$j×$i=${i * j}\t")
        println()           //另起一行
    }
}

Kotlin的for循環(huán)相當(dāng)于Java的foreach循環(huán),但for循環(huán)中的變量無需用varval聲明刷晋,for-in循環(huán)可用于對范圍或者集合進(jìn)行遍歷盖高。結(jié)合生成遞減數(shù)列的中綴運(yùn)算符,可以實現(xiàn)更復(fù)雜的功能眼虱。

fun main(args: Array<String>) {
    for(i in 15 downTo 1 step 3)
        println(i)
}

上述代碼中的downTo是生成一個遞減數(shù)列喻奥,而step則是設(shè)置數(shù)列的步長。

帶標(biāo)簽的break和continue

與Java類似捏悬,Kotlin也支持帶標(biāo)簽的break和continue語句撞蚕,語法是在forwhiledo前面加上標(biāo)簽名@过牙,使用標(biāo)簽時用break/continue@標(biāo)簽名甥厦,如:

fun main(args: Array<String>) {
    label1@ for (x in 0..10) {
        for (y in 10 downTo 5 step 3) {
            if(x % 2 == 0) continue@label1
            if(y == x) break@label1
            println("(x, y)=($x, $y)")
        }
    }
}

Kotlin運(yùn)算符

算術(shù)運(yùn)算符纺铭、邏輯運(yùn)算符和關(guān)系運(yùn)算符

Kotlin的算術(shù)運(yùn)算符、邏輯運(yùn)算符與Java一致刀疙,關(guān)系運(yùn)算符與Java稍有不同彤蔽,其中==運(yùn)算符對兩個對象進(jìn)行比較,調(diào)用的是對象的equals()函數(shù)庙洼,!=則是對==運(yùn)算符的取反;而對引用類型的比較則需使用===!==運(yùn)算符镊辕,用于判斷兩個引用是否指向同一個對象油够。當(dāng)一個對象與null進(jìn)行顯式的比較時,使用兩種運(yùn)算符效果相同征懈,Kotlin會自動將==轉(zhuǎn)換為===石咬。

位運(yùn)算符
名稱 Java位運(yùn)算符 Kotlin位運(yùn)算符 示例
位取反 ~ inv a.inv()
位與 & and a and b 或 a.and(b)
位或 | or a or b 或 a.or(b)
位異或 ^ xor a xor b 或 a.xor(b)
左移 << shl a shl b 或 a.shl(b)
有符號右移 >> shr a shr b 或 a.shr(b)
無符號右移 >>> ushr a ushr b 或 a.ushr(b)

Java和Kotlin的位運(yùn)算符和Kotlin位運(yùn)算符的示例如下表所示:

名稱 Java位運(yùn)算符 Kotlin位運(yùn)算符 示例
位取反 ~ inv a.inv()
位與 & and a and b 或 a.and(b)
位或 | or a or b 或 a.or(b)
位異或 ^ xor a xor b 或 a.xor(b)
左移 << shl a shl b 或 a.shl(b)
有符號右移 >> shr a shr b 或 a.shr(b)
無符號右移 >>> ushr a ushr b 或 a.ushr(b)
其他運(yùn)算符

前面的介紹中提到了非空斷言運(yùn)算符!!、安全調(diào)用運(yùn)算符?.卖哎、安全轉(zhuǎn)換運(yùn)算符as?鬼悠、Elvis運(yùn)算符?:等,Kotlin的y一些運(yùn)算符是通過調(diào)用轉(zhuǎn)換方法來實現(xiàn)的亏娜,下表介紹了一些運(yùn)算符及其轉(zhuǎn)換方法:

  • 一元運(yùn)算符
名稱 運(yùn)算符 轉(zhuǎn)換方法 作用
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
自增 a++或++a a.inc()
自減 a--或--a a.dec()
引用 :: 引用類焕窝、屬性或函數(shù)
展開 * 用于將數(shù)組傳遞給可變參數(shù)
  • 二元運(yùn)算符
名稱 運(yùn)算符 轉(zhuǎn)換方法 作用
相加 a + b a.plus(b)
相減 a - b a.minus(b)
相乘 a * b a.times(b)
相除 a / b a.div(b)
取余 a % b a.mod(b)
區(qū)間 a..b a.rangeTo(b)
比較 >、<维贺、>=它掂、<= a.compareTo(b) 比較兩個對象,通過返回值的正負(fù)判斷大小
a in b b.contains(a) 判斷a是否在b中
a !in b !b.contains(a)
相等 a == b a?.equals(b) ?: (b === null)
不等 a != b !(a?.equals(b) ?: (b === null))
調(diào)用 a(i) a.invoke(i)
調(diào)用 a(i, j) a.invoke(i, j)
調(diào)用 a(i_1, … , i_n) a.invoke(i_1, …, i_n)
索引訪問 a[i] a.get(i)
索引訪問 a[i, j] a.get(i, j)
索引訪問 a[i_1, …, i_n] a.get(i_1, …, i_n)
索引訪問 a[i] = b a.set(i, b)
索引訪問 a[i, j] = b a.set(i, j, b)
索引訪問 a[i_1, …, i_n] = b a.set(i_1, …, i_n, b)

局部函數(shù)和匿名函數(shù)

Kotlin的函數(shù)可以聲明在類內(nèi)部溯泣,稱為成員函數(shù)虐秋,還可以聲明在另一函數(shù)的內(nèi)部,稱為局部函數(shù)垃沦。當(dāng)函數(shù)只被調(diào)用一次時客给,可以聲明為匿名函數(shù)。

fun main(args: Array<String>) {
    println(calculate(1.0, 2.0))
    println(calculate(1.0, 2.0, '-'))
    println(calculate(1.0, 2.0,'*'))
    println(calculate(1.0, 2.0, '/'))
    println(calculate(2.0, 1.0, '%'))
}

fun calculate(n1: Double, n2: Double, operator: Char = '+'): Double {
    //resultFun是一個函數(shù)類型的變量肢簿,
    val resultFun: (Double, Double) -> Double = when (operator) {
        '+' -> fun(a: Double, b: Double): Double { return a + b }
        '-' -> fun(a, b) = a - b
        '*' -> { a: Double, b: Double -> a * b }
        '/' -> { a, b -> a / b }
        else -> { _, _ ->
            println("輸入數(shù)據(jù)錯誤")
            0.0
        }
    }
    return resultFun(n1, n2)
}

上述代碼中使用了when表達(dá)式靶剑、參數(shù)默認(rèn)值和命名參數(shù)、函數(shù)類型變量池充、匿名局部函數(shù)抬虽、表達(dá)式函數(shù)體、Lambda表達(dá)式和類型推斷纵菌。

Kotlin支持函數(shù)類型阐污,可以定義函數(shù)類型的變量,類似C語言中的函數(shù)指針咱圆,允許把函數(shù)作為參數(shù)傳遞笛辟,這是Kotlin對Java反射機(jī)制的增強(qiáng)實現(xiàn)功氨,反射機(jī)制內(nèi)容較多,這里只對函數(shù)類型進(jìn)行說明:函數(shù)類型的格式為:(參數(shù)數(shù)據(jù)類型列表) -> 返回值類型手幢,例如:() -> Unit表示空參數(shù)列表無返回值的函數(shù)類型捷凄,(Double, Double) -> Double表示兩個浮點(diǎn)型參數(shù),返回值為浮點(diǎn)型的函數(shù)類型围来。

上述代碼五個分支全部使用了匿名局部函數(shù)跺涤,其中"+"分支是省略了函數(shù)名(匿名)的局部函數(shù),"-"分支進(jìn)一步將使用表達(dá)式函數(shù)體簡化了函數(shù)體并省略參數(shù)和返回值類型的聲明(Kotlin會根據(jù)定義的接收函數(shù)的變量的類型進(jìn)行推斷)监透,"*"桶错、"/"else分支使用了Lambda表達(dá)式。

Lambda表達(dá)式是一種特殊的匿名函數(shù)胀蛮,它是一個函數(shù)對象院刁,其聲明方式為{ 參數(shù)列表 -> 語句塊 },Lambda表達(dá)式內(nèi)部的返回值是語句塊的最后一行粪狼,Lambda表達(dá)式的參數(shù)列表類型也支持自動推斷退腥,當(dāng)某個參數(shù)在語句塊中沒有用到的時候,可以通過下劃線_占位再榄,如else分支狡刘,當(dāng)Lambda只有一個參數(shù)時,可以省略參數(shù)困鸥,只寫語句塊颓帝,其中唯一的參數(shù)(隱式參數(shù))用it標(biāo)識符代替。

Kotlin約定,在調(diào)用函數(shù)時,如果使用Lambda表達(dá)式作為參數(shù)堆生,若Lambda表達(dá)式是最后一個參數(shù),可以將Lambda表達(dá)式塊移到參數(shù)列表括號的后面瘪板,而當(dāng)只有這一個參數(shù)時,前面的小括號可以省略漆诽,如:

fun main(args: Array<String>) {
    test({ x:Int, y:Int -> x + y })
    test() { x, y -> x - y }
    test { a, b -> a * b }
}

fun test(block: (a: Int, b: Int) -> Int) {
    println(block(1, 2))
}

數(shù)組

基本數(shù)據(jù)類型數(shù)組
Kotlin基本數(shù)據(jù)類型數(shù)組 Java基本數(shù)據(jù)類型數(shù)組
IntArray int[]
LongArray long[]
FloatArray float[]
DoubleArray double[]
ShortArray short[]
ByteArray byte[]
CharArray char[]
BooleanArray boolean[]

Kotlin基本數(shù)據(jù)類型數(shù)組和Java基本數(shù)據(jù)類型數(shù)組的對應(yīng)關(guān)系如下表所示:

Kotlin基本數(shù)據(jù)類型數(shù)組 Java基本數(shù)據(jù)類型數(shù)組
IntArray int[]
LongArray long[]
FloatArray float[]
DoubleArray double[]
ShortArray short[]
ByteArray byte[]
CharArray char[]
BooleanArray boolean[]

Kotlin的數(shù)組都是通過使用頂層函數(shù)創(chuàng)建的侮攀,基本數(shù)據(jù)類型數(shù)組有3種創(chuàng)建方式,以Int類型為例厢拭,它們的函數(shù)聲明如下:

  1. intArrayOf(varag element: Int):這里的varag表示這是一個可變參數(shù)兰英,可變參數(shù)必須位于參數(shù)列表的最后一個,調(diào)用時需要提供零個或多個Int類型的數(shù)據(jù)
  2. IntArray(size: Int):該函數(shù)通過指定數(shù)組的元素個數(shù)創(chuàng)建數(shù)據(jù)類型默認(rèn)值的數(shù)組供鸠,Int的默認(rèn)值是0
  3. IntArray(size: Int, init: (Int) -> Int):該函數(shù)第一個參數(shù)指定數(shù)組大小畦贸,第二個參數(shù)提供一個(Int) -> Int類型的函數(shù),通常使用Lambda表達(dá)式,函數(shù)的第一個參數(shù)是數(shù)組的下標(biāo)(從0開始)
    val a = intArrayOf(1, 0, 0, 8, 6)               //產(chǎn)生由1, 0, 0, 8, 6構(gòu)成的基本數(shù)據(jù)類型數(shù)組
    val b = intArrayOf(*a, 1, 1)                    //*是展開運(yùn)算符薄坏,產(chǎn)生由1, 0, 0, 8, 6, 1, 1構(gòu)成的基本數(shù)據(jù)類型數(shù)組
    val c = DoubleArray(8)                          //產(chǎn)生8個0.0構(gòu)成的基本數(shù)據(jù)類型數(shù)組
    val d = CharArray(26) { (it + 65).toChar() }    //產(chǎn)生26個大寫字母構(gòu)成的基本數(shù)據(jù)類型數(shù)組
    d[0] = 'a'                                      //通過調(diào)用set()函數(shù)為數(shù)組單個成員賦值
對象數(shù)組
Kotlin對象數(shù)組 Java包裝類數(shù)組
Array<Int> java.lang.Integer[]
Array<Long> java.lang.Long[]
Array<Float> java.lang.Float[]
Array<Double> java.lang.Double[]
Array<Short> java.lang.Short[]
Array<Byte> java.lang.Byte[]
Array<Char> java.lang.Character[]
Array<Boolean> java.lang.Boolean[]

Kotlin中的對象數(shù)組對應(yīng)Java中的包裝類數(shù)組趋厉,其對應(yīng)關(guān)系為:

Kotlin對象數(shù)組 Java包裝類數(shù)組
Array<Int> java.lang.Integer[]
Array<Long> java.lang.Long[]
Array<Float> java.lang.Float[]
Array<Double> java.lang.Double[]
Array<Short> java.lang.Short[]
Array<Byte> java.lang.Byte[]
Array<Char> java.lang.Character[]
Array<Boolean> java.lang.Boolean[]

對象數(shù)組也有3種創(chuàng)建方式,以Int類型為例:

  1. arrayOf(varag elements: T):創(chuàng)建類型為T的數(shù)組變量胶坠,提供一組相同數(shù)據(jù)類型的數(shù)據(jù)列表
  2. arrayOfNulls<T>(size: Int)size參數(shù)用于指定創(chuàng)建數(shù)組的大小君账,該函數(shù)用于創(chuàng)建一個類型為T的數(shù)組,所有的元素均為空值
  3. Array(size:Int, init: (Int) -> T):該函數(shù)第一個參數(shù)指定數(shù)組大小沈善,第二個參數(shù)提供一個(Int) -> T類型的函數(shù)乡数,通常使用Lambda表達(dá)式,函數(shù)的第一個參數(shù)是數(shù)組的下標(biāo)(從0開始)
fun main(args: Array<String>) {
    val array2D = Array(3) { arrayOfNulls<Int>(5) }
    println(array2D.indices)            //數(shù)組的indices屬性是數(shù)組的下標(biāo)區(qū)間
    println(array2D[0].indices)
    //遍歷方式1
    for(i in array2D)
        for(j in i)
            println(j)
    //遍歷方式2
    for(i in array2D.indices)
        for(j in array2D[0].indices)
            println(array2D[i][j])
}

需要本教程MarkDown版本的請聯(lián)系QQ:2336233438
轉(zhuǎn)發(fā)請注明原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闻牡,一起剝皮案震驚了整個濱河市净赴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌澈侠,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埋酬,死亡現(xiàn)場離奇詭異哨啃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)写妥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門拳球,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人珍特,你說我怎么就攤上這事祝峻。” “怎么了扎筒?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵莱找,是天一觀的道長。 經(jīng)常有香客問我嗜桌,道長奥溺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任骨宠,我火速辦了婚禮浮定,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘层亿。我一直安慰自己桦卒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布匿又。 她就那樣靜靜地躺著方灾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碌更。 梳的紋絲不亂的頭發(fā)上迎吵,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天躲撰,我揣著相機(jī)與錄音,去河邊找鬼击费。 笑死拢蛋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔫巩。 我是一名探鬼主播谆棱,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼圆仔!你這毒婦竟也來了垃瞧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤坪郭,失蹤者是張志新(化名)和其女友劉穎个从,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歪沃,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗦锐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沪曙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕污。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖液走,靈堂內(nèi)的尸體忽然破棺而出碳默,到底是詐尸還是另有隱情,我是刑警寧澤缘眶,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布嘱根,位于F島的核電站,受9級特大地震影響巷懈,放射性物質(zhì)發(fā)生泄漏儿子。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一砸喻、第九天 我趴在偏房一處隱蔽的房頂上張望柔逼。 院中可真熱鬧,春花似錦割岛、人聲如沸愉适。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽维咸。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間癌蓖,已是汗流浹背瞬哼。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留租副,地道東北人坐慰。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像用僧,于是被迫代替她去往敵國和親结胀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容