而我熟悉Java,所以在學(xué)習(xí)Swift時,就會將Swift與Java進(jìn)行比較,思考。(文中的示例代碼均來自The Swift Programming Language)
從Java到Swift還是比較簡單的,相比Object-C,Swift和Java的語法更加接近,和最近的Kotlin就更像了。Swift同時支持面向?qū)ο缶幊毯秃瘮?shù)式編程。Swift比Java功能更加強大,用法更加友好。網(wǎng)上有一份Java和Swift的粗略對比:
1.Swift沒有main函數(shù),這個有點像腳本語言。Swift程序的默認(rèn)入口是main.swift文件,在iOS應(yīng)用中,則通常標(biāo)記了@UIApplicationMain的AppDelegate.swift文件??梢灶惐鹊紸ndroid中,在AndroidManifest.xml中定義的Application。
2.Swift不需要定義行結(jié)束符,這個是像腳本語言一樣。
3.Swift使用var定義變量,一般無需指定具體的數(shù)據(jù)類型,編譯器會自行判斷。遇到編譯器無法判斷的情況,需要自己顯式指定。
//Java定義變量 int x = 0; //Swift定義變量,編譯器自動識別數(shù)據(jù)類型 var x = 0; //Swift定義變量,顯式指定類型,否則此時編譯器會自動識別成Int var y : Long = 0;
4.Swift用let定義常量,Java里面是static final。
5.array跟Java中的array是一樣的概念。dictionary就是Java中的map。dictionary的取值的方式是dictionary[key],接口就像array一樣,簡潔方便。
6.nil在swift中就類似Java中的null。nil是沒有初始化成功,是沒有值。
7.optional value是指該value的值可以是nil,Swift默認(rèn)一個var是不能賦值nil,除非它聲明了optional。optional不能直接輸出,而必須unwrap,形如optionalValue!。有點類似于Java中打包好的null判斷。也可以用!代替?聲明一個無需unwrap的var。
1.Swift的switch 語法和Java及C++很像,但是它沒有break,他命中一個case后會自動退出switch。對于幾個不同case同樣處理的情況,可以case后面連續(xù)幾個condition,用逗號隔開。
switch value { case condition1: response to condition 1 case condition2, condition3: resoponse to condition 2 or 3 default: otherwise, do something else }2.Swift的switch支持運算,運算的話,就是說不僅僅是equal,而是支持滿足特定要求。
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") } // prints "(1, -1) is on the line x == -y"
3.while循環(huán)和Java或者C++中基本一致,不過while后面直接寫condition,不需要用括號。
4.for循環(huán)和Java也基本一樣,不過也是不需要括號。for循環(huán)中,..<的用法比較方便。下劃線符號_(替代循環(huán)中的變量)能夠忽略具體的值,并且不提供循環(huán)遍歷時對值的訪問。for-in則有點類似與Java中for each循環(huán)。
1.函數(shù)的定義和Java很不一樣。Swift函數(shù)的定義形如 func functionName(argName: Type) -> Return Type:
func sayHelloAgain(personName: String) -> String { return "Hello again, " + personName + "!" }2.Swift函數(shù)可以返回多個返回值,這個功能真是太猛了。
func minMax(array: [Int]) -> (min: Int, max: Int) { var currentMin = array[0] var currentMax = array[0] for value in array[1..<array.count] { if value < currentMin { currentMin = value } else if value > currentMax { currentMax = value } } return (currentMin, currentMax) }3.Swift函數(shù)可以接收不定參數(shù),跟Java基本類似的用法。
func chooseStepFunction(backwards: Bool) -> (Int) -> Int { func stepForward(input: Int) -> Int { return input + 1 } func stepBackward(input: Int) -> Int { return input - 1 } return backwards ? stepBackward : stepForward }5.Swift支持函數(shù)類型,根據(jù)輸入?yún)?shù)和返回值確定一個函數(shù)類型。函數(shù)類型可以讓函數(shù)像,普通數(shù)據(jù)類型一樣使用。例如函數(shù)的參數(shù)可以另外一個函數(shù),注意,不是另外一個函數(shù)的返回值,而是另外一個函數(shù),只要類型符合即可。這個相當(dāng)于是函數(shù)級別的多態(tài),真的有點猛。
//定義一個函數(shù),類型是(Int, Int)->Int func addTwoInts(a: Int, _ b: Int) -> Int { return a + b } //定義另一個函數(shù),其中一個參數(shù)是(Int, Int) -> Int函數(shù) func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) { print("Result: \(mathFunction(a, b))") } //直接將addTwoInts()作為printMathResult()的參數(shù) printMathResult(addTwoInts, 3, 5)
6.Swift支持閉包,我覺得可以理解成“匿名函數(shù)”,只需要描述輸入輸出,用in分開輸入輸出描述,已經(jīng)函數(shù)體,無需定義函數(shù)名。
1.類的構(gòu)造函數(shù),直接叫init()。類函數(shù)調(diào)用跟Java,C++基本一樣。self相當(dāng)于Java中的this。
2.在Swift中class的成員訪問權(quán)限控制級別有public, internal, private,類似Java中的public, protected, private。
3.deinit是析構(gòu)函數(shù)。Java中也有finalize()函數(shù)。不過Java的finalize()函數(shù)并不確保一定被調(diào)用,所以并不推薦override該函數(shù)。
4.類的繼承跟C++有點像,使用:。
class SomeSubclass: SomeSuperclass { // subclass definition goes here }5.他的setter和getter函數(shù)跟Java不太一樣,是隱式調(diào)用的。我覺得Swift的設(shè)計思想是,用戶只需關(guān)心輸入和輸出,其他的不用關(guān)心。例如此處只需關(guān)心需要set或者get。具體的set和get函數(shù)則是封裝的,無需使用者去關(guān)心。又譬如上面提到的method的type,只要定義了輸入和輸出,就定義了一類method,那就可以對這種type有多種具體實現(xiàn)。
struct Point { var x = 0.0, y = 0.0 } struct Size { var width = 0.0, height = 0.0 } struct Rect { var origin = Point() var size = Size() var center: Point { get { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return Point(x: centerX, y: centerY) } set(newCenter) { origin.x = newCenter.x - (size.width / 2) origin.y = newCenter.y - (size.height / 2) } } } var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0)) let initialSquareCenter = square.center square.center = Point(x: 15.0, y: 15.0) print("square.origin is now at (\(square.origin.x), \(square.origin.y))")6.Swift的枚舉和Java類似,本質(zhì)是一個類,里面可以包含函數(shù)。
enum Barcode { case UPCA(Int, Int, Int, Int) case QRCode(String) } var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)9.protocol類似于Java中的interface。
extension Double { var km: Double { return self * 1_000.0 } var m: Double { return self } var cm: Double { return self / 100.0 } var mm: Double { return self / 1_000.0 } var ft: Double { return self / 3.28084 } } let oneInch = 25.4.mm print("One inch is \(oneInch) meters") // prints "One inch is 0.0254 meters" let threeFeet = 3.ft print("Three feet is \(threeFeet) meters") // prints "Three feet is 0.914399970739201 meters"11.Swift泛型和Java類似的,Swift的泛型支持where語句,可以在對類型控制之外,作更加精細(xì)的控制。
func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, _ anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { return false } // check each pair of items to see if they are equivalent for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // all items match, so return true return true }
Swift和Java類似,也無需自己管理內(nèi)存,Swift是由ARC(Automatic Reference Counting)機制來回收內(nèi)存的,Java是有垃圾回收機制來保證內(nèi)存被及時回收。但是兩者的回收機制有所區(qū)別。我的理解是Swift的ARC機制著眼于無效的對象,就是那些沒有被任何人引用到的對象。因此,如果兩個對象循環(huán)引用,就會無法被回收,引起泄露。此時就需要Weak Reference或者Unowned Reference來打破這個環(huán)。
下圖中Person對象和Apartment對象由于互相強引用,無法被ARC回收。
而Java的垃圾回收機制,從反面思考,著眼于哪些是有效的對象,即有被GC Root引用到的對象是有效的,其他的都是無效的。因此哪怕有對象相互引用,只要沒有被GC Root引用到,都會被垃圾回收器回收掉(如下圖所示)。從這此處來看,Java的策略更優(yōu)。也由此可以看到換個角度看問題是多么重要。