介紹Kotlin第二部分(翻譯篇)

前言

Kotlin介紹:第一部分虹茶,我們介紹了基本語法旗芬,現(xiàn)在我們可以去看看實(shí)際上如何使用Kotlin。在這篇文章中续扔,我們將介紹collectionslambdas表達(dá)式攻臀,一些方便的擴(kuò)展函數(shù)(applylet纱昧,runwith)刨啸,null safety(空安全),那下面咱就開始吧识脆。

1设联、Collections and Lambdas

那么Kotlin collections是什么呢?如果您熟悉Java8灼捂,您將會(huì)對(duì)這些collection方法(java流)和語法十分了解离例。然而,Kotlin提供了大部分你可能想得到的擴(kuò)展悉稠,讓我們一起來看看吧粘招。

listOf(1,2,3)
mutableListOf("a", "b", "c")
 
setOf(1,2,3)
mutableSetOf("a", "b", "c")
 
mapOf(1 to "a", 2 to "b", 3 to "c")
mutableMapOf("a" to 1, "b" to 2, "c" to 3)

這些是基礎(chǔ),Kotlin為您提供了方法來創(chuàng)建collections偎球,我在這兒列出了不可變和可變版本的List洒扎,Set和Map。Kotlin系列的編程除了默認(rèn)的不變性外衰絮,還來自于Kotlin stdlib的擴(kuò)展功能袍冷。如果您熟悉函數(shù)式編程,那么您將熟悉大部分功能猫牡。它們是一組輔助函數(shù)和更高級(jí)的輔助函數(shù)胡诗,可以為您的集合提供常用操作。有了這些擴(kuò)展函數(shù)(map淌友,flatMap煌恢,forEachfold震庭,reduce瑰抵,filterzip器联,...)很多操作完成起來就很方便二汛。
在我們使用它們之前,我們需要先說一下lambdas表達(dá)式拨拓。Kotlin標(biāo)準(zhǔn)庫的collection擴(kuò)展功能的優(yōu)點(diǎn)來自于易使用lambdas表達(dá)式肴颊,只需使用足夠的類型推理來保證編程安全。在Kotlin中有幾種方法來定義lambdas函數(shù)渣磷。

val aList = listOf(1,2,4)
aList.map { elem ->
    elem + 1
} // 2,3,5
 
aList.filter { it != 1} // 2,4
 
fun folder(a: Int, b: Int) = a + b
aList.reduce(::folder) // 7
// 或者: aList.reduce { a, b -> folder(a, b) }

在第一個(gè)例子中婿着,我們定義了Kotlin lambdas的最常見用法。我們可以用角括號(hào)(->)來縮寫匿名函數(shù),我們可以改變lambdas參數(shù)的名稱(在這里我們省略了類型定義竟宋;我們可以從aList列表中看到它是一個(gè)Int)奥务,然后我們定義lambda體,不需要使用return語句袜硫,最后一行將被返回。

下一個(gè)例子進(jìn)一步說明挡篓,甚至可以省略參數(shù)定義婉陷。在Kotlin中,默認(rèn)情況下官研,一個(gè)參數(shù)lambdas會(huì)接收到一個(gè)名為it的參數(shù)名秽澳。沒有必要去命名它。請(qǐng)注意戏羽,如果過多的使用it担神,尤其在嵌套函數(shù)中,會(huì)導(dǎo)致代碼非呈蓟ǎ混亂妄讯!

最后一個(gè)向我們展示了幾個(gè)新的概念,首先是一個(gè)本地函數(shù)酷宵,我們引用了::一個(gè)雙匯語法亥贸,本地函數(shù)的樣式和作用類似于類或全局作用域函數(shù),但還有一個(gè)額外功能浇垦,它還能訪問與函數(shù)本身在同一范圍定義的變量炕置。引用本地函數(shù)的第二種方法我們將它稱為內(nèi)部lambda,就像注釋中顯示的那樣男韧。

正如你所看到的朴摊,Kotlin中的lambdas是以直截了當(dāng)?shù)姆绞蕉x的。它們?cè)谀拇a中也很明顯此虑,并使得高階函數(shù)的使用變得簡(jiǎn)單甚纲。關(guān)于Kotlin和lambdas的最好部分是類型推斷,當(dāng)類型不匹配時(shí)朦前,它就在你的代碼下面出現(xiàn)一條紅色的線贩疙。通過編譯器的這種幫助,您可以將精力放在業(yè)務(wù)邏輯上况既,而不是試圖找出循環(huán)應(yīng)該遍歷多少遍这溅。

有關(guān)Kotlin的collection擴(kuò)展功能的更多信息可以在官方網(wǎng)站API doc中找到

2、Null safety(空安全)

當(dāng)涉及到可空性棒仍,Kotlin編譯器會(huì)非常嚴(yán)格的剖析您的代碼悲靴。如果定義一個(gè)可能為null的變量,則需要將其定義為可空莫其。那這該怎么寫呢癞尚?

var nil: String? = null
val notNil: String = "Hi"
var nil = null

這三個(gè)變量聲明有兩個(gè)可空值耸三,一個(gè)不為null。無效性的共同點(diǎn)是問號(hào)浇揩;可空變量和函數(shù)參數(shù)用問號(hào)定義仪壮。這個(gè)問號(hào)在Kotlin的null safe起著重要的作用。如果Kotlin編譯器在變量聲明或函數(shù)參數(shù)/返回類型中看到這個(gè)問號(hào)胳徽,它將強(qiáng)制您對(duì)空檢查积锅。如果您主要編寫的是Kotlin代碼,那您將會(huì)從NullPointException解放出來养盗。然而Kotlin與Java高度互操作缚陷,當(dāng)你傳入的數(shù)據(jù)可能為空時(shí)。Kotlin會(huì)讓你處理這個(gè)十億美元的錯(cuò)誤往核。

data class Lad(val name: String, val age: Int)
fun doSomething(laddy: Lad?){
    print(laddy.name)
}

如果您嘗試這么做箫爷,Kotlin會(huì)編譯器將會(huì)給出提示。在android studio中聂儒,您將得到文本下方的紅色波浪線虎锚,它會(huì)給出Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Lad?。為了解決這個(gè)問題衩婚,你別無選擇翁都。

fun doSomething(laddy: Lad?){
    if(laddy != null){
        print(laddy.name)
    }
}
 
fun doSomething(laddy: Lad?){
    print(laddy?.name)
}
 
fun doSomething(laddy: Lad?){
    laddy?.name?.let {
        print(it)
    }
    /** 或者
    * laddy?.name?.let { name ->
    *     print(name)
    * }
    **/
}

第一個(gè)例子是之前的寫法,正確的非空檢查谅猾。編譯器知道员淫,在完成null檢查之后迅耘,就可以使用我們的變量瞎颗,紅色波浪線就會(huì)從print語句中消失婉徘。在第二個(gè)例子,我們熟悉的問號(hào)再次出現(xiàn)了敬矩,但是這一次擔(dān)任是不同的角色概行。在這方面,問號(hào)會(huì)提示If laddy is not null, then take the name property from it弧岳。如果laddy為空凳忙,那么null將會(huì)打印到控制臺(tái)。

第三個(gè)介紹了一個(gè)擴(kuò)展功能禽炬,我們可以用它來調(diào)用let涧卵。如果我們想從我們的函數(shù)返回一些東西,我們可以使用elvis作為默認(rèn)值腹尖,以防我們碰到一個(gè)null柳恐。使用elvis有點(diǎn)像這樣:

fun doSomething(laddy: Lad?) = laddy?.name?: "James"

當(dāng)laddy和name都不為空時(shí),才會(huì)返回“James”。

3乐设、擴(kuò)展功能(Apply, Let, Run, and With)

Kotlin推出了一些擴(kuò)展功能讼庇,可以幫助我們處理。我們看到的第一個(gè)let是一個(gè)擴(kuò)展近尚,它將一個(gè)lambda作為參數(shù)蠕啄。在上面的例子中,it意味著我們的對(duì)象屬性name戈锻,但僅當(dāng)laddy和name不為空時(shí)有效歼跟。let只對(duì)存在的東西有用,作為擴(kuò)展功能舶沛,它不能擴(kuò)展不存在的東西。

Apply是另一個(gè)時(shí)髦的擴(kuò)展功能窗价,我們可以在很多情況下使用它如庭,一個(gè)常見的用法的就是創(chuàng)建一個(gè)需要許多調(diào)用的對(duì)象,但是沒有很好的方法來做到這一點(diǎn)撼港。為了簡(jiǎn)單起見坪它,我們能想到JavaBean及其getter和seeter。

public class JavaBeanClass {
   private String thing;
   private String thang;
 
   public String getThing() {           
       return thing;                    
   }                                    
                                        
   public void setThing(String thing) { 
       this.thing = thing;              
   }                                    
                                        
   public String getThang() {           
       return thang;                    
   }                                    
                                        
   public void setThang(String thang) { 
       this.thang = thang;              
   }                                    
}

這看起來有點(diǎn)繁瑣帝牡,沒關(guān)系往毡,讓我們使用Kotlin看看。

val mrBean = JavaBeanClass().apply {
    setThing("Wild")
    setThang("erbeest")
}

這就很舒服了靶溜,其實(shí)在Kotlin中开瞭,還可以有其它的寫法,與上述相同的代碼還可以這么寫:

val mrBean = JavaBeanClass().apply {
    thing = "Wild"
    thang = "erbeest"
}

這樣就更簡(jiǎn)潔了罩息。

接下來我們介紹with嗤详,這個(gè)家伙類似apply,實(shí)際上它不是一個(gè)擴(kuò)展函數(shù)瓷炮,它只是一個(gè)函數(shù)葱色,接受了兩個(gè)參數(shù)。我們來看一個(gè)例子娘香,我們將使用與mrBean之前定義的相同的方法苍狰。

with(mrBean) {
    thing = "the"
    thang = "ain't no"
}

和apply非常相似,你不覺得嗎烘绽?其實(shí)根本不一樣淋昭,那是因?yàn)槲覀儧]有做任何事,with返回with塊中最后一個(gè)表達(dá)式的值安接。這是一個(gè)重要的區(qū)別响牛,所以讓我們看一個(gè)更好的例子。

val yo = with(mrBean) {
    thang + "thing"
}
print(yo) // ain't nothing

我們繼續(xù)看下一個(gè)操作符run,這是一個(gè)很簡(jiǎn)單的小東西呀打。它是一個(gè)擴(kuò)展函數(shù)矢赁,它接受一個(gè)參數(shù),一個(gè)lambda贬丛。它只是調(diào)用該lambda并返回該lambda的響應(yīng)撩银。“那么這個(gè)家伙有什么用呢豺憔?” “你可能會(huì)問”额获。使用它來運(yùn)行某些東西,當(dāng)且僅當(dāng)它被調(diào)用的對(duì)象不是null(使用它類似于let上面的幾行恭应,但在run這種情況下this作為范圍的對(duì)象)或使用它來調(diào)用我們的函數(shù)調(diào)用并保護(hù)我們的lambdas抄邀。我們必須記住,做run同樣的事情昼榛,但with通常更容易使用境肾。

4、類型: Checking, casting, and safety(檢查胆屿,轉(zhuǎn)換奥喻,安全)

在Java世界中,您可能會(huì)遇到這樣的if檢查if (clazz instanceOf SomeClass)程序員希望看到他們是否正確實(shí)現(xiàn)其接口或擴(kuò)展的基類非迹。
在Kotlin中類型推斷是非常好的环鲤,編譯器在編寫代碼時(shí)給出了很多有用的提示。當(dāng)您需要檢查對(duì)象是否是某種類型時(shí)憎兽,您可以使用is關(guān)鍵字冷离。

fun tryAndFailToCompileToGetTheAnswer(plzPassInThirteen: Any): Int {
    return plzPassInThirteen + 29
}
 
fun getTheAnswer(plzPassInThirteen: Any): Int {
    if (plzPassInThirteen is Int) {
        return plzPassInThirteen + 29
    }
    return 666
}
println(getTheAnswer(13)) // 42

在上面的代碼塊中,第一個(gè)函數(shù)將會(huì)失敗纯命,并且根本沒有實(shí)際編譯酒朵,它會(huì)報(bào)錯(cuò),找不到類型匹配扎附。第二個(gè)功能修復(fù)了:它做了一個(gè)簡(jiǎn)單的is檢查蔫耽,在這一點(diǎn)上,Kotlin智能的將該值轉(zhuǎn)換為Int留夜,因此它可以在if語句中使用匙铡。通常當(dāng)when和is配合使用時(shí),您可以這么寫:

fun getTheAnswer(plzPassInThirteen: Any): Int = when(plzPassInThirteen) {
    is Int -> plzPassInThirteen + 29
    else -> 666
}
println(getTheAnswer(13)) // 42

這個(gè)例子與以前看到的if語句是一樣的碍粥,但這不是更美觀嗎鳖眼?

現(xiàn)在我們接觸了iswhen在一起,現(xiàn)在我們可以繞個(gè)彎子談一談sealed classes嚼摩,Kotlin有一個(gè)sealed classes的概念钦讳,我們可以把它當(dāng)成一些子類的包裝矿瘦。

sealed class Seal
class SeaLion: Seal()
class Walrus: Seal()
class KissFromARose(val film: String): Seal()

如果我們有這樣的結(jié)構(gòu),一個(gè)密封的超類和三個(gè)繼承的子類愿卒,我們可以很好的處理多態(tài)和when以及is的組合缚去。

fun getTheAnswer(songOrAnimal: Seal): Unit = when(songOrAnimal) {
    is SeaLion -> println("Animal")
    is Walrus -> println("Song by Beatles")
}

這是編譯不過去的,編譯器會(huì)告訴我們when中的聲明少了哪一個(gè)子類琼开,如果我們將KissFromARose添加上就不會(huì)出現(xiàn)問題易结。

fun getTheAnswer(songOrAnimal: Seal): Unit = when(songOrAnimal) {
    is SeaLion -> println("Animal")
    is Walrus -> println("Song by Beatles")
    is KissFromARose -> ("Heidi Klum")
}
println(getTheAnswer(Walrus())) // Song by Beatles

上面的編譯就沒什么問題,

有時(shí)候我們需要類型的轉(zhuǎn)換柜候,在Kotlin中搞动,使用as關(guān)鍵字。當(dāng)它被賦值時(shí)渣刷,我們可以假設(shè)它被轉(zhuǎn)換為該類型鹦肿,

val possiblyString: Any = "definitely"
possiblyString.capitalize()

上面的例子是無法編譯的,capitalize()會(huì)有錯(cuò)誤下劃線辅柴,編譯器告訴我們有一個(gè)Unresolved reference和resolver type mismatch箩溃。這個(gè)提示是對(duì)的,我們知道Any沒有capitalize()方法碌识,修改這個(gè)是容易的碾篡,我們只要將變量變成String就沒問題了虱而。

val possiblyString: Any = "definitely"
possiblyString as String
possiblyString.capitalize()

現(xiàn)在我們已經(jīng)了解了Kotlin的集合筏餐,空安全類型安全牡拇,到這里第二部分的內(nèi)容也算是告一段落了魁瞪。

快樂工作,享受編程惠呼!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末导俘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子剔蹋,更是在濱河造成了極大的恐慌旅薄,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泣崩,死亡現(xiàn)場(chǎng)離奇詭異少梁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矫付,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門凯沪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人买优,你說我怎么就攤上這事妨马⊥伲” “怎么了?”我有些...
    開封第一講書人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵烘跺,是天一觀的道長(zhǎng)湘纵。 經(jīng)常有香客問我,道長(zhǎng)液荸,這世上最難降的妖魔是什么瞻佛? 我笑而不...
    開封第一講書人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮娇钱,結(jié)果婚禮上伤柄,老公的妹妹穿的比我還像新娘。我一直安慰自己文搂,他們只是感情好适刀,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著煤蹭,像睡著了一般笔喉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上硝皂,一...
    開封第一講書人閱讀 49,906評(píng)論 1 290
  • 那天常挚,我揣著相機(jī)與錄音,去河邊找鬼稽物。 笑死奄毡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贝或。 我是一名探鬼主播吼过,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼咪奖!你這毒婦竟也來了盗忱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤羊赵,失蹤者是張志新(化名)和其女友劉穎趟佃,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昧捷,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闲昭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了料身。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汤纸。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芹血,靈堂內(nèi)的尸體忽然破棺而出贮泞,到底是詐尸還是另有隱情楞慈,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布啃擦,位于F島的核電站囊蓝,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏令蛉。R本人自食惡果不足惜聚霜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望珠叔。 院中可真熱鬧蝎宇,春花似錦、人聲如沸祷安。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汇鞭。三九已至凉唐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霍骄,已是汗流浹背台囱。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留读整,地道東北人簿训。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绘沉,于是被迫代替她去往敵國(guó)和親煎楣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豺总,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

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