Kotlin 君和 Swift 君在一個(gè)團(tuán)隊(duì)一起開發(fā)已經(jīng)很久了累舷,由于平臺(tái)的差異性躲雅,他們經(jīng)常會(huì)進(jìn)行一些技術(shù)上的交流(PK)劫乱,「Kotlin vs. Swift」系列就是他們?cè)诨ハ嗲写钑r(shí)的語錄巡李。
技術(shù)漫談
Kotlin:
Hi澄者,Swift 君笆呆,今天我們繼續(xù)煮酒論道吧
Swift:
好请琳,那我們今天就切磋一下控制流吧, 你們是怎么做條件判斷的赠幕?
Kotlin:
我們用 if
做條件判斷俄精,一般傳統(tǒng)的形式是這樣的:
var max: Int
if (a > b) {
max = a
} else {
max = b
}
Swift:
嗯,這與我們一樣榕堰,我們可以省略 if
后面的小括號(hào) ()
Kotlin:
但是我們 if
語句可以用作表達(dá)式竖慧,可以有值返回,如 val b = if (a > 0) a else 0
Swift:
這也沒啥局冰,與我們的三目運(yùn)算符如出一轍测蘑,var b = a > 0 ? a : 0
半斤八兩,沒啥好炫耀的.
Kotlin:
額康二。碳胳。。好吧沫勿,那我們 if
做表達(dá)式的時(shí)候后面也可以接代碼塊挨约,在塊代碼中隨后一行的輸出會(huì)作為該塊代碼的返回值,如下:
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
你行嗎产雹?
Swift:
這诫惭。。蔓挖。夕土,算你牛×
Kotlin:
哈哈瘟判,服了吧怨绣,需要注意的是,if
在用作表達(dá)式的時(shí)候拷获,后面必須提供 else
從句篮撑。
Swift:
哦,我們的 if
語句和大多數(shù)語言類似匆瓜,沒有啥花哨的東西赢笨,但是我們除了 if
做條件判斷外,還可以用 guard
語句, 形式如下:
guard <condition> else {
<statements>
}
Kotlin:
這看著和 if
語句差不多嘛驮吱,有啥區(qū)別呢茧妒?
Swift:
舉個(gè)栗子你就明白了
if 版本:
func greet(person: [String: String]) {
if let name = person["name"] {
print("Hello \(name)")
if let location = person["location"] {
print("weather is nice in \(location).")
} else {
print("weather is nice near you.")
}
} else {
print("Hello stranger")
}
}
guard 版本:
func greet(person: [String: String]) {
guard let name = person["name"] else {
print("Hello stranger")
return
}
print("Hello \(name)")
guard let location = person["location"] else {
print("weather is nice near you.")
return
}
print("weather is nice in \(location).")
}
對(duì)比可以看出,guard
版本更清晰易讀糠馆,if
版本的一連串的 if/else
讓人頭暈嘶伟。
Kotlin:
贊,說白了又碌,guard
就是把不符合條件的處理事件前置九昧,提前退出绊袋,避免了代碼金字塔的出現(xiàn),使代碼看起來更優(yōu)雅铸鹰,更易讀癌别。不過跟你說個(gè)小秘密,我們自己封裝個(gè)類似 guard
的函數(shù)蹋笼。
Swift:
2333展姐,不過我們使用 guard
語句的時(shí)候也必須要有 else
從句
Kotlin:
嗯嗯,來說說你們是怎么做條件匹配的
Swift:
我們用 switch
語句來進(jìn)行條件匹配剖毯,例如:
let x = 1
switch x {
case 1:
print("x == 1")
case 2:
print("x == 2")
default:
print("x is neither 1 nor 2")
}
Kotlin:
差不多圾笨,我們是用 when
來進(jìn)行條件匹配,意思是一樣的:
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個(gè)塊
print("x is neither 1 nor 2")
}
}
Swift:
嗯~ o(* ̄▽ ̄*)o
逊谋,語法不一樣而已擂达,看上去你們的更簡(jiǎn)潔一些嘛。
Kotlin:
當(dāng)有不同的分支需要同樣的處理的話胶滋,可以用逗號(hào)分隔寫在一起板鬓。
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
Swift:
我的寫法也一樣:
switch x {
case 0, 1:
print("x == 0 or x == 1")
default:
print("otherwise")
}
當(dāng)匹配到的 case
中的代碼執(zhí)行完畢后,switch
語句會(huì)直接退出究恤,而不會(huì)繼續(xù)執(zhí)行下一個(gè) case
俭令,如果確實(shí)想執(zhí)行下一個(gè) case
,我們也提供了相應(yīng)的方法部宿。
Kotlin:
這也可以抄腔?什么方法?
Swift:
就是顯式的在當(dāng)前 case
中使用 fallthrough
語句理张。例如:
let x = 5
var description = "\(x) is"
switch x {
case 2, 3, 5, 7, 11:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 輸出 "5 is a prime number, and also an integer."
Kotlin:
我們沒有這個(gè)功能妓柜,不過這種貫穿功能似乎也不常用嘛。
Swift:
是的涯穷,不常用不代表沒有用嘛。switch
還可以匹配一個(gè)值的區(qū)間藏雏。例如:
switch x {
case 1..<10:
print("single digit")
case 10...99:
print("double digit")
default:
print("out of range")
}
Kotlin:
when
也可以:
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Swift:
哇~, 你們還可以直接在一個(gè)匹配模式之前加 !
操作符,好強(qiáng)大蹲嚣,我們不可以车摄。
Kotlin:
牛吧,不僅如此奏寨,when
可以不提供參數(shù)起意,直接順序匹配滿足條件的表達(dá)式后,執(zhí)行其對(duì)應(yīng)后面的表達(dá)式病瞳。
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
Swift:
厲害了揽咕,我們不行悲酷,我們 switch
后必須要有參數(shù)。
Kotlin:
哈哈亲善,服了吧
Swift:
不服设易,看來不給你點(diǎn)厲害的瞧瞧,不知道馬王爺有幾只眼蛹头!
Kotlin:
(⊙?⊙)
Swift:
我們可以使用元組在同一個(gè) switch
語句中測(cè)試多個(gè)值顿肺。元組中的元素可以是值,也可以是區(qū)間渣蜗。另外屠尊,可以使用下劃線(_
)來匹配所有可能的值。例如:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"
Kotlin:
贊耕拷!我們沒有元組類型讼昆,雖然 Kotlin 也提供了類似的析構(gòu)功能,但還是沒有你們這么靈活斑胜,所以也就沒有這種模式匹配控淡。
Swift:
不僅如此,case
分支還允許將匹配的值綁定到一個(gè)臨時(shí)的常量或變量止潘,并且在 case
分支體內(nèi)使用:
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 輸出 "on the x-axis with an x value of 2"
Kotlin:
牛掺炭!
Swift:
switch
分支的模式還可以使用 where
語句來判斷額外的條件。如下:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"
這時(shí)候當(dāng)且僅當(dāng)控制表達(dá)式匹配一個(gè) case
的模式且 where
子句的表達(dá)式為真時(shí)凭戴,case
中的語句才會(huì)被執(zhí)行.
Kotlin:
請(qǐng)收下我的膝蓋涧狮。。么夫。
Swift:
哈哈者冤,接下來我們切磋一下循環(huán)語句吧
Kotlin:
好,Kotlin
的 for
循環(huán)和 while
循環(huán)與 Java
里面的語法差別不大档痪,不過得益于 Kotlin
的析構(gòu)功能涉枫,我們可以在迭代中方便的使用多個(gè)參數(shù)。
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
Swift:
我們也有類似的寫法腐螟。
for (index, value) in array.enumerated() {
print("the element at \(index) is \(value)")
}
除了 for-in
語句外愿汰, 我們也有 while
和 repeat-while
來實(shí)現(xiàn)循環(huán)遍歷。
Kotlin:
你的 repeat-while
是不是和我們的 do-while
一樣乐纸?
Swift:
是的衬廷,一模一樣。
Kotlin:
Kotlin
提供了靈活的標(biāo)簽功能汽绢,在跳轉(zhuǎn)表達(dá)式出現(xiàn)歧義的時(shí)候吗跋,可以支持以標(biāo)簽的方式制定跳轉(zhuǎn)表達(dá)式要跳轉(zhuǎn)的位置,如在嵌套循環(huán)中。例如:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
Swift:
我們也有類似的標(biāo)簽功能跌宛。
var sum = 0
rowLoop: for row in 0..<8 {
columnLoop: for column in 0..<8 {
if row == column {
continue rowLoop
}
sum += row * column
}
}
Kotlin:
嗯嗯酗宋,看上去就是標(biāo)簽的定義方式不一樣,我們要多寫一個(gè) @
.
不過我們的標(biāo)簽還可以用在函數(shù)中秩冈,例如:
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
Swift:
我們不能
Kotlin:
甚至我們還可以使用隱式的標(biāo)簽本缠。
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
Swift:
嗯,你們的標(biāo)簽功能比我們強(qiáng)大入问。
Kotlin:
好了丹锹,今天我們就到此為止吧,和你交流還是收獲頗豐的芬失。
Swift:
(^-^)V楣黍,青山不改,綠水長(zhǎng)流棱烂,咱們江湖再見租漂。
Kotlin:
后會(huì)有期。
知識(shí)點(diǎn)總結(jié)
Kotlin
條件判斷
在 Kotlin 中用 if
做判斷有兩種用法颊糜,一種是用作傳統(tǒng)的條件判斷哩治,另一種是做為表達(dá)式。
當(dāng)用作傳統(tǒng)的條件判斷的時(shí)候衬鱼,跟 Java 沒有什么差異业筏。
var max: Int
if (a > b) {
max = a
} else {
max = b
}
當(dāng) if
用作表達(dá)式的時(shí)候,可以有值返回鸟赫,如 val b = if (a > 0) a else 0
蒜胖。這樣的用法很像 Java 里的三目運(yùn)算,所以在 Kotlin 里面就沒有再單獨(dú)提供三目運(yùn)算了抛蚤。
當(dāng) if
作為表達(dá)式的時(shí)候后面也可以接塊代碼台谢,在塊代碼中隨后一行的輸出會(huì)作為該塊代碼的返回值。
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
需要注意的是岁经,在用作表達(dá)式的時(shí)候朋沮,后面必須提供 else
。
when 表達(dá)式
Kotlin 用 when 表達(dá)式替代 Java 里面的 switch-case缀壤,不過不僅僅是替代朽们,when 表達(dá)式提供了更加強(qiáng)大的功能。
普通的條件匹配
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個(gè)塊
print("x is neither 1 nor 2")
}
}
when 會(huì)順序比較所有的條件诉位,匹配到合適的以后機(jī)會(huì)執(zhí)行條件后面對(duì)應(yīng)的表達(dá)式(類似 if也可以是塊),當(dāng)所有的條件都不滿足的時(shí)候就會(huì)執(zhí)行 else 后面的表達(dá)式菜枷。所有的when 表達(dá)式中都要提供 else苍糠,除非 Kotlin 能推斷出不會(huì)再有其他條件存在。
當(dāng)有不同的分支需要同樣的處理的話啤誊,可以用逗號(hào)分隔寫在一起岳瞭。
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
匹配任意表達(dá)式
when 不僅支持常量的條件匹配拥娄,還可以支持任意表達(dá)式的匹配,所以你可以這樣肆無忌憚的使用它來匹配某個(gè)數(shù)是否在某某范圍瞳筏。
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
或者匹配未知類型的類型稚瘾。
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
無參數(shù)匹配
when 可以不提供參數(shù),直接順序匹配滿足條件的表達(dá)式后姚炕,執(zhí)行其對(duì)應(yīng)后面的表達(dá)式摊欠。
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
循環(huán)
Kotlin 的 for 循環(huán)和 while 循環(huán)和 Java 里面的語法差別不大,不過得益于 Kotlin 的析構(gòu)功能柱宦,我們可以在迭代中方便的使用多個(gè)參數(shù)些椒。
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
帶標(biāo)簽的返回(return)、中斷(break)和繼續(xù)(continue)
Kotlin 提供了靈活的標(biāo)簽功能掸刊,在跳轉(zhuǎn)表達(dá)式出現(xiàn)歧義的時(shí)候免糕,可以支持以標(biāo)簽的方式制定跳轉(zhuǎn)表達(dá)式要跳轉(zhuǎn)的位置,如在嵌套循環(huán)中忧侧。
loop@ for (i in 1..100) {
for (j in 1..100) {
if (……) break@loop
}
}
或者在函數(shù)中,
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
甚至我們還可以使用隱式的標(biāo)簽石窑。
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
Swift
條件判斷
swift
使用 if
語句或 guard
語句來做條件判斷。if
語句與 c
語言等其他類型語句沒有差別蚓炬。guard
則是把不符合條件的處理事件前置松逊,提前退出,避免了代碼金字塔的出現(xiàn)试吁,使代碼看起來更優(yōu)雅棺棵,更易讀。
例如:
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
不同于 if
語句熄捍,一個(gè) guard
語句必須要有一個(gè) else
從句與之配對(duì)烛恤。
Switch 語句
swift
用 switch
語句來進(jìn)行條件匹配,例如:
let x = 1
switch x {
case 1:
print("x == 1")
case 2:
print("x == 2")
default:
print("x is neither 1 nor 2")
}
任何類型的值都可以作為控制表達(dá)式的值余耽。當(dāng)有不同的分支需要同樣的處理的話缚柏,可以將這個(gè)幾個(gè)值組合成一個(gè)復(fù)合匹配,并且用逗號(hào)分開碟贾,如下:
switch x {
case 0, 1:
print("x == 0 or x == 1")
default:
print("otherwise")
}
Fallthrough
當(dāng)匹配到的 case
中的代碼執(zhí)行完畢后币喧,switch
語句會(huì)直接退出,而不會(huì)繼續(xù)執(zhí)行下一個(gè) case
袱耽,如果確實(shí)想執(zhí)行下一個(gè) case
杀餐,需要顯式的在當(dāng)前 case
中使用 fallthrough
語句。例如:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 輸出 "The number 5 is a prime number, and also an integer."
元組
可以使用元組在同一個(gè) switch
語句中測(cè)試多個(gè)值朱巨。元組中的元素可以是值史翘,也可以是區(qū)間。另外,可以使用下劃線(_
)來匹配所有可能的值琼讽。例如:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("(0, 0) is at the origin")
case (_, 0):
print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 輸出 "(1, 1) is inside the box"
值綁定
不僅如此必峰,case
分支還允許將匹配的值綁定到一個(gè)臨時(shí)的常量或變量,并且在 case
分支體內(nèi)使用:
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 輸出 "on the x-axis with an x value of 2"
where 子句
switch
分支的模式可以使用 where
語句來判斷額外的條件钻蹬, 例如:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// 輸出 "(1, -1) is on the line x == -y"
這時(shí)候當(dāng)且僅當(dāng)控制表達(dá)式匹配一個(gè) case
的模式且 where
子句的表達(dá)式為真時(shí)吼蚁,case
中的語句才會(huì)被執(zhí)行.
循環(huán)語句
Swift
中的循環(huán)語句包括:for-in
, while
和 repeat-while
, while
與其他語言的 while
無二, repeat-while
則與 do-while
一致问欠。
for-in
語句的形式如下:
for <item> in <collection> {
<statements>
}
可以使用 for-in
語句來遍歷一個(gè)序列肝匆,例如數(shù)組中的元素、數(shù)字范圍或者字符串中的字符等.
使用 for-in
語句遍歷一個(gè) Dictionary
來訪問其鍵值對(duì)溅潜,如下:
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
for-in
還可以用來遍歷一個(gè)數(shù)字范圍术唬,例如:
for index in 1...10 {
print("\(index)")
}
帶標(biāo)簽的語句
在swift
中,可以使用標(biāo)簽來標(biāo)記一個(gè)循環(huán)語句或 switch
語句滚澜。對(duì)于一個(gè) switch
語句粗仓,可以使用 break
加標(biāo)簽的方式,來結(jié)束這個(gè)被標(biāo)記的語句设捐。對(duì)于一個(gè)循環(huán)語句借浊,可以使用 break
或 continue
加標(biāo)簽,來結(jié)束或者繼續(xù)執(zhí)行這條被標(biāo)記的語句萝招。
var sum = 0
rowLoop: for row in 0..<8 {
columnLoop: for column in 0..<8 {
if row == column {
continue rowLoop
}
sum += row * column
}
}