標籤:swift 物件導向編程
Swift是Apple最新推出的語言,用於編寫iOS和OS X程式,與C語言和Objective-C相容。本系列的文章中的一些例子,都來自於蘋果官方的GUIDE: The Swift Programming Language,有興趣的同學可以去蘋果的官網下載英文原版的iBook。
一、Hello world
Swift中不需要main函數,也不需要用;分開每一行的語句,一個簡單的Hello world如下所示:
println("Hello, world")
二、賦值
使用let來建立一個常量,使用var來建立一個變數,如下所示:
var myVariable = 42myVariable = 50let myConstant = 42
如果初始值沒有提供足夠多的類型資訊,需要用冒號來定義變數類型:
let implicitInt = 72let implicitDouble = 72.0let explicitDouble : Double = 72
如上所示,變數可以隱式定義類型,也可以用冒號來顯式定義類型。
但是,變數在初始化之外,永遠都不會隱式轉換類型的。例如有變數:
let label = "number is "let num = 5
那麼,下面的語句是錯的:
let numLabel = label + num
原因是字串不能與整型相加,那麼正確的寫法應該是:
let numLabel = label + String(num)
有一種更簡單的方法來包含需要轉換的值,就是在雙引號中使用反斜線\來擷取變數的字串型值:
let numLabel = "number is \(num)"
可以用方括弧[ ]來建立詞典和數組:
var shoppingList = ["catfish", "water"]shoppingList[1] = "bottle of water"var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic",]occupations["Jayne"] = "Public Relations"
用初始化器建立一個空白的詞典或列表:
let emptyArray = [String]()let emptyDictionary = Dictionary<String, Float>()
當數組或類型的值可以被推斷出來時,可以用[ ] 代表一個空白數組,用[:]代表一個空白詞典。
三、流程式控制制
1、if、switch case條件控制
if、switch中的條件不需要括弧,且switch語句中的case不需要加break,因為case中的語句不會跳轉到下一個case中。例如:
let hello = "hello"switch hello {case "hello": let lang = "English"case "你好": let lang = "Chinese"default: let lang = "other"}let score = 62if score >= 60 { let result = "Passed"} else { let result = "No pass"}
if語句中的條件一定要為布爾值,而不是像C語言那樣傳入0和非0即可。
2、for、for-in、while、do while迴圈控制
迴圈語句中的條件同樣無需添加括弧。當在for-in語句中使用一對值時,可以對辭典的鍵、值進行迭代,例如下面是一個返回辭典中最大值的代碼:
let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25],]var largest = 0for (kind, numbers) in interestingNumbers{ for number in numbers{ if number > largest { largest = number } }}largest
可以在for語句中用..<來簡化代碼的編寫,以下是兩段等效的代碼:
for i in 0..<4{ }for var i=0; i < 4; ++i { }
四、函數和閉包
使用func定義一個函數,用 -> 表示函數的傳回型別,類似於C++11中的函數傳回型別後置。函數形參與類型直接用冒號隔開,形參與形參之間用逗號隔開。
func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)."}greet ("Froser", "Sunday")
可以使用元組(Tuple)來使函數返回多個值:
func getNumber() -> (Double, Double) { return (1.0, 2.0)}
可以使用...來接收不定長參數,這些不定長參數將作為一個列表:
func sumOf(numbers: Int...) -> Int { var sum = 0; for number in numbers { sum += number }}sumOf()sumOf(1,3,100)
函數可以被嵌套,被嵌套的函數可以訪問外部函數的變數:
func test() -> Int { var x = 10 func add(){ x += 5 } add() return x}
函數也是一種類型,例如,我們可以讓一個函數返回另外一個函數並調用它。
func makeIncrement() -> (Int -> Int) { func increase(number: Int) -> Int { return number + 1 } return increase}
如上所示,makeIncrement返回一個接受一個參數為Int,返回值為Int的函數。在C++中,如果要返回函數,一般是返回函數的地址,在C#中,我們可以把內部的嵌套函數作為一個Lambda運算式來返回,也可以返回一個函數的委託。
同理,函數的形參也可以為函數:
func equals (numberA: Int, numberB: Int, equals: (Int, Int) -> Bool ) -> Bool { return equals(numberA, numberB)}
Swift支援匿名函數,你可以把匿名函數看成一個變數,只不過它可以被調用而已。匿名函數不能包含函數名,且要用in來分開函數簽名和函數體:
object.save({ (number: Int) -> Int in let result = 3 * number return result })
五、類與對象
使用class關鍵字來建立一個類,類內部可以添加變數、常量和方法(Method)
class Shape{ var numberOfSides = 0 func description() -> String { return "A shape with \(numbeOfSides) sides." }}
如同一般的物件導向編程,用“.”訪問對象中的成員。
var shape = Shape()shape.numberOfSides = 7
使用init方法來為類建立一個構造器,用deinit為類建立一個析構器。
就像C++、C#那樣,通過在類名稱後面加冒號可以表示類的繼承。如果子類要覆蓋一個基類方法,必須要加上關鍵字override。意外地覆蓋了基類方法卻沒有加override會導致編譯器報錯。
class A{ func test(){}}class B : A{ override func test(){}}
可以像C#那樣,在類中定義屬性,並編寫它們的get和set方法:
class A{ var _property : String = "" var property : String{ get{ return "hello " + _property } set{ _property = newValue } }}
在為property賦值時,會調用set方法,取值時會調用get方法。set方法中的newValue表示property被賦予的值。
除此之外,Swift還定義了兩種屬性方法:willSet和didSet,分別代表屬性賦值前和賦值後執行的方法。
Swift中,類中的func被稱為“方法(Method)”,方法可以訪問類成員中的值:
class Counter { var count: Int = 0 func add() { count++ }}
六、枚舉
使用enum關鍵字建立一個枚舉類型,並用case定義它的枚舉值。枚舉類型可以看成是一個類,因為它可以包含自己的方法,當調用自身方法時,一個使用self擷取自身的資訊:
enum Rank: Int { case Ace = 1 case Two, Three, Four func description() -> String { switch self { case .Ace: return "ace" default: return String(self.toRaw()) } }}
如上所示,我們定義了枚舉類型Rank,並為它定義了其原始類型為Int。如果原始類型不重要,你也可以不提供,即去掉“: Int”,此時你亦不可為枚舉成員賦予初值。
當編譯器能夠推斷出枚舉對象的類型時,不必在賦值時加上枚舉類型名,如可以將Rank.Ace簡化為.Ace。
枚舉成員甚至可以帶參數:
enum ServerResponse{ case Success(String) case Error(String)}let error = ServerResponse.Error("Password incorrect!")
七、結構
使用關鍵字struct建立一個結構,與“類”不同的是,結構在傳遞時,是按照值傳遞的,而拷貝則是按照“引用”來傳遞的。請參考C#、Java中的值傳遞、引用傳遞。
八、協議
協議如同C#、Java中的“介面(Interface)”:
protocol Example{ var description: String { get } mutating func adjust()}
繼承了此協議的類、結構,都必須實現description屬性的get方法,以及adjust方法。
在結構中,實現adjust方法必須在前面添加關鍵字mutating,表示它會改變自身內部成員的值,而class本身就可以改變自身成員的值,就不必添加了:
class ClassWithDescription : Example { var description: String= "very simple" func adjust(){ description="" }}struct StructWithDescription : Example { var description: String= "very simple" mutating func adjust(){ description="" }}
如同物件導向設計那樣,可以用Example類型來定義任何繼承了Example協議的對象,但是它只會包含Example協議中的細節。
九、擴充
如同C#中的擴充方法、Objective-C中的類別,使用extension關鍵字到一個已知類型,我們可以為這種類型添加擴充的屬性、方法。
extension Int: Example{ ....}extension Int{ ....}
十、泛型
Swift中有泛型函數、泛型方法、泛型結構、泛型枚舉、泛型結構等。泛型的類型寫在角括弧<>中:
func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType] { var result = [ItemType]() for i in 0..<times{ result += item } return result}repeat ("knock", 4)
可以在角括弧中加入where來約束泛型:
func test<T where T: Sequence> (arg: T){ ....}
十一、總結
以上是列舉了一些Swift的文法點,可見Swift吸取了很多語言的成功經驗:如Javascript的動態與隨意性、C#的屬性機制、泛型機制、Java的枚舉機制、C++11的後置類型返回,以及簡化了for迴圈的一些寫法(這個可能是和Perl學的),讓它能成為一門真正的物件導向動態型語言。
之後,我會將Swift語言中的每一個細節都整理出來,希望能和大家一起學習。