這篇文章是想著幫助Android開發快速學習Swift編程語言用的. (因為這個文章的作者立場就是這樣.) 我不想寫一個非常長, 非常詳盡的文章, 只是想寫一個快速的版本能讓你快速上手工作. ...
Swift vs Kotlin
這篇文章是想著幫助Android開發快速學習Swift編程語言用的. (因為這個文章的作者立場就是這樣.)
我不想寫一個非常長, 非常詳盡的文章, 只是想寫一個快速的版本能讓你快速上手工作.
當然這個文章可能也適合於以下人群:
- 有經驗的其他任何語言的開發者, 想學Swift.
- 一個會Swift的iOS開發者, 想橫向對比, 瞭解學習一下Kotlin.
- iOS初級程式員, 剛開始學習.
- 用過Swift, 但是有一陣子沒用了, 想快速刷新一下回憶.
基本類型
Swift | Kotlin |
---|---|
Bool | Boolean |
Array | Array, List, MutableList |
Set | Set |
Dictionary | Map |
其他基本類型都是差不多的.
語法
Swift | Kotlin | |
---|---|---|
變數聲明 | let/var | val/var |
具名參數 | at: 0 | at = 0 |
函數/方法 | func name() → returnType | fun name(): returnType |
表達無值 | nil | null |
unwrapped type | String! | - |
if | if number != nil | if(number != null) |
為空時提供預設值 | xxx ?? “default string” | ? : ”default string” |
不為空時做某件事 | if let number = Int(”333”) {} | ?.let {} |
for loop | for i in 1...5 {} | for (i in 1..5) {} |
for loop | for i in 1..<5 {} | for (i in 1 until 5) {} |
do while loop | repeat {} while | do {} while () |
this instance | self | this |
value object | struct | data class |
as? | as? | |
as! | as | |
try? | - | |
try! | - | |
class initializer | initializer | constructor |
init a mutable list | var someInts: [Int] = [] | val someInts = mutableListOf |
init a empty dictionary/map | var namesOfIntegers: [Int: String] = [:] | val namesOfIntegers = mutableMapOf<Int, String>() |
Constants and Variables
Swift:
let
不能再次賦值. 如果對象類型是struct
, 不能更新對象的任何欄位. 如果是class
, 則仍可更新對象的var
欄位.var
可以給變數重新賦值, 也可以更新變數的var
欄位.var
可以聲明一個mutable的集合類型.
Kotlin:
val
和java中的final
等價, 不能再給變數重新賦值, 但是仍然可以更新對象的var
欄位.var
意味著可以給變數重新賦值.- 集合類型的可變與否是被具體的集合類型聲明所決定的.
Switch case
Swift:
var x = 3
switch x {
case 1: print("x == 1")
case 2, 4: print("x == 2 or x == 4")
default: print("x is something else")
}
Kotlin:
val x = 3
when (x) {
1 -> print("x == 1")
2, 4 -> print("x == 2 or x == 4")
else -> print("x is something else")
}
String interpolation
Swift:
var name = "Mike"
print("Hello \(name)")
也可以給String規定格式:
let str = NSString(format:"%d , %f, %ld, %@", 1, 1.5, 100, "Hello World")
print(str)
Kotlin:
var name = "Mike"
println("Hello $name")
val str = String.format("%d, %f, %d, %s", 1, 1.5, 100, "Hello World")
print(str)
Function and Closure
Swift的function有一個argument label
:
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
這裡parameterName
是方法內部使用的, argumentLabel
是被外部調用者使用的. (目的是為了增強可讀性.)
當argument label沒有提供的時候, parameter name同時也扮演argument label的角色.
在方法調用時argument label 預設是不能省略的(雖然有時候它和parameter name一樣), 如果你想在調用的時候省略, 可以用下劃線_
明確指明.
Closure
閉包和Kotlin中的lambda相似.
一個簡單的Swift例子:
let sayHello = { (name: String) -> String in
let result = "Hello \(name)"
print(result)
return result
}
sayHello("Mike")
用Kotlin做同樣的事情:
val sayHello : (String) -> String = { name: String ->
val result = "Hello $name"
print(result)
result
}
sayHello("Mike")
相同點:
- 可以根據上下文推斷類型, 所以有時候類型可以省略.
- 可以作為另一個函數的參數傳入, 從而實現高階方法.
- 如果閉包/lambda是方法的最後一個參數, 可以提到圓括弧外面. 如果是唯一的參數, 可以省略圓括弧.
不同點:
- 在Swift中,只有單句表達式可以省略
return
關鍵字, 把表達式結果作為返回值. 而在Kotlin中, 最後的表達式值會被作為返回結果, 且在lambda中沒有return
關鍵字. - Swift有縮略版本的參數名, 比如:
$0
,$1
,$2
.
Custom types
Swift | Kotlin |
---|---|
class | class |
protocol | interface |
extension | extension methods |
class
Swift和Kotlin中的類定義和用法十分相似.
繼承是通過:
符號, 子類可以override
父類的方法.
繼承的的時候父類class需要放在protocol前.
只有構造看起來有點不同, 在Swift中叫initializer:
class Person {
let name: String
init(name: String = "") {
self.name = name
}
}
let p1 = Person()
print("\(p1.name)") // default name: ""
let p2 = Person(name: "haha")
print("\(p2.name)")
在Kotlin中, 可以通過如下的代碼達到相同的目的:
class Person(val name: String = "") {
}
val p1 = Person()
print("${p1.name}") // default name: ""
val p2 = Person(name="haha")
print("${p2.name}")
struct
struct是一個值類型.
struct和class的區別:
- class可以繼承.
- struct是值類型: 拷貝多份不會共用數據; class是引用類型, 所有的賦值拷貝最終都指向同一份數據實例.
- class有
deinit
. - class的實例可以被
let
保存, 同時實例的var
欄位仍然可被修改, struct則不可修改.
class Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
print("\(p1.name)")
這是ok的.
如果Person
是struct:
struct Person {
var name = "Lily"
}
let p1 = Person()
p1.name = "Justin"
// Compiler error: Cannot assign to property: `p1` is a `let` constant
編譯器會報錯.
想要改變欄位值, 只能聲明: **var** p1 = Person()
.
protocol
protocol類似Kotlin中的interface
.
我們可以定義一些方法或者計算屬性作為契約.
Properties寫起來是這樣的:
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
protocol和interface有一點點小區別: 比如實現protocol的類的方法上不需要使用override
關鍵字.
extension
在Swift, extension更像是一個用來放擴展方法和屬性的地方.
extension String {
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}
mutating func trim() {
self = self.trimmed()
}
var lines: [String] {
self.components(separatedBy: .newlines)
}
}
在Kotlin中擴展方法可以是頂級方法, 只需要在.
之前聲明類型:
fun String.someMethod() : String {
return this.trim()
}
enum
Swift enum:
enum CompassPoint {
case north
case south
case east
case west
}
多個case也可以寫在一行, 用逗號分隔:
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
在Swift中使用枚舉的時候, 我們可以省略前面的類型, 只用一個.
開頭:
var directionToHead = CompassPoint.west
directionToHead = .east
Swift enum有一個allCases
屬性, 暴露所有case的集合.
Kotlin:
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
在枚舉中我們也可以定義方法和屬性, 這個Swift和Kotlin是一樣的.
Optionals
雖然Swift的optional type和Kotlin的nullable type看起來是類似的(都是具體類型後面加個問號), 但實際上它們還是有點不同.
Swift的optional type更像Java的Optional
.
因為你在用之前永遠需要解包(unwrap).
var someString : String? = nil
print(someString?.count) // print nil
print(someString!.count) // Fatal error: Unexpectedly found nil while unwrapping an Optional value
當變數有值時, 我們需要用它:
var someString : String? = "Hello"
if (someString != nil) {
print("\(someString) with length \(someString?.count)")
// print: Optional("Hello") with length Optional(5)
print("\(someString!) with length \(someString!.count)")
// print: Hello with length 5
}
註意當直接用的時候, 變數的類型永遠是Optional.
必須解包才能拿到值.
實際上在Swift中有一種更簡單的寫法來做這件事, 使用if let
:
if let someStringValue = someString {
print("\(someStringValue) with length \(someStringValue.count)")
}
這裡someStringValue
是從someString
解包過的值, 後面的block只有當它不為nil時才會被執行.
在Kotlin中:
var someString : String? = null
print(someString?.length) // print null
print(someString!!.length) // NullPointerException
不同點主要在於有值的時候:
var someString : String? = "Hello"
if(someString != null) {
print("$someString with length: ${someString.length}")
}
// print: Hello with length: 5
在Kotlin中, 如果我們判斷過變數不為null, 後面就可以直接用了, 編譯器知道這個變數現在不為空了.
if let 和 guard let
我們上面的例子用if let
解包Optional, 只在不為nil的時候執行大括弧裡面的內容.
guard let
做的事情正好相反: else
block只在值為nil的時候才執行:
func printSquare(of number: Int?){
guard let number = number else {
print("Oops we got nil")
return
}
print("\(number) * \(number) is \(number * number)")
}
所以guard let
通常被用來做參數檢測, 不合法就return.
並且在guard語句之後, number不再是一個optional的類型, 是一個確定有值的類型.
最後
學習新的語言的時候, 不太建議花太多的時間鑽研語言的每個細節.
只需要瞭解一些最基本的知識, 然後就可以上手做具體的工作和任務.
在實際的任務中進行進一步的學習和練習.
總之, 希望這篇文章對你有用.
References
- Swift book: https://docs.swift.org/swift-book/
出處: 博客園: 聖騎士Wind
Github: https://github.com/mengdd
微信公眾號: 聖騎士Wind
