Swift結構體與類
在麵向過程的編程語言(如C語言)中,結構體用得比較多,但是麵向對象之後,如在C++和Objective-C中,結構體已經很少使用了。這是因為結構體能夠做的事情,類完全可以取而代之。而Swift語言卻非常重視結構體,把結構體作為實現麵向對象的重要手段。Swift中的結構體與C++和Objective-C中的結構體有很大的差別,C++和Objective-C中的結構體隻能定義一組相關的成員變量,而Swift中的結構體不僅可以定義成員變量(屬性),還可以定義成員方法。因此,我們可以把結構體看做是一種輕量級的類。
Swift中的類和結構體非常類似,都具有定義和使用屬性、方法、下標和構造器等麵向對象特性,但是結構體不具有繼承性,也不具備運行時強製類型轉換、使用析構器和使用引用計等能力。
一、類和結構體定義
Swift中的類和結構體定義的語法也是非常相似的。我們可以使用class關鍵詞定義類,使用struct關鍵詞定義結構體,它們的語法格式如下:
class 類名 {
定義類的成員
}
struct 結構體名 {
定義結構體的成員
}
從語法格式上看,Swift中的類和結構體的定義更類似於Java語法,不需要像C++和Objective-C那樣把接口部分和實現部分放到不同的文件中。
類名、結構體名的命名規範與枚舉類型的要求是一樣的。下麵我們來看一個示例:
class Employee { //定義員工類
var no : Int = 0 //定義員工編號屬性
var name : String = "" //定義員工姓名屬性
var job : String? //定義工作屬性
var salary : Double = 0 //定義薪資屬性
var dept : Department? //定義所在部門屬性
}
struct Department { //定義部門結構體
var no : Int = 0 //定義部門編號屬性
var name : String = "" //定義部門名稱屬性
}
Employee是我們定義的類,Department是我們定義的結構體。在Employee和Department中我們隻定義了一些屬性。關於屬性的內容我們將在下一章介紹。
Employee和Department是有關聯關係的,Employee所在部門的屬性dept與Department關聯起來,它們的類圖如下圖所示。

我們可以通過下列語句實例化:
var emp = Employee()
var dept = Department()
Employee()和Department()是調用它們的構造器實現實例化,關於構造器我們會在14.1節介紹。
提示 實例化之後會開辟內存空間,emp和dept被稱為“實例”,但隻有類實例化的“實例”才能被稱為“對象”。事實上,不僅僅是結構體和類可以實例化,枚舉、函數類型和閉包開辟內存空間的過程也可以稱為實例化,結果也可以叫“實例”,但不能叫“對象”。
二、再談值類型和引用類型
數據類型可以分為:值類型和引用類型,這是由賦值或參數傳遞方式決定的。值類型就是在賦值或給函數傳遞參數時候,創建一個副本,把副本傳遞過去,這樣在函數的調用過程中不會影響原始數據。引用類型就是在賦值或給函數傳遞參數的時候,把本身數據傳遞過去,這樣在函數的調用過程中會影響原始數據。
在眾多的數據類型中,我們隻需記住:隻有類是引用類型,其他類型全部是值類型。即便結構體與類非常相似,它也是值類型。值類型還包括整型、浮點型、布爾型、字符串、元組、集合和枚舉。
Swift中的引用類型與Java中的引用類型是一樣的,Java中的類也是引用類型。如果你沒有Java經驗,可以把引用類型理解為C、C++和Objective-C語言中的指針類型,隻不過不需要在引用類型變量或常量前麵加星號(*)。
下麵我們看一個示例:
var dept = Department() ① dept.no = 10 dept.name = "Sales" ② var emp = Employee() ③ emp.no = 1000 emp.name = "Martin" emp.job = "Salesman" emp.salary = 1250 emp.dept = dept ④ func updateDept (dept : Department) { ⑤ dept.name = "Research" ⑥ } println("Department更新前:\(dept.name)") ⑦ updateDept(dept) ⑧ println("Department更新後:\(dept.name)") ⑨ func updateEmp (emp : Employee) { ⑩ emp.job = "Clerk" ⑪ } println("Employee更新前:\(emp.job)") ⑫ updateEmp(emp) ⑬ println("Employee更新後:\(emp.job)") ⑭
上述代碼第①~②行創建Department結構體實例,並設置它的屬性。代碼第③~④行創建Employee類實例,並設置它的屬性。
為了測試結構體是否是值類型,我們在第⑤行代碼定義了updateDept函數,它的參數是Department結構體實例。第⑥行代碼dept.name = "Research"是改變dept實例。然後在第⑦行打印更新前的部門名稱屬性,在第⑧行進行更新,在第⑨行打印更新後的部門名稱屬性。如果更新前和更新後的結果一致,則說明結構體是值類型,反之則為引用類型。事實上第⑥行代碼會有編譯錯誤,錯誤信息如下。
Playground execution failed: error: <REPL>:34:15: error: cannot assign to 'name' in 'dept'
dept.name = "Research"
~~~~~~~~~ ^
這個錯誤提示dept.name = "Research"是不能賦值的,這說明了dept結構體不能修改,因為它是值類型。其實有另外一種辦法可以使值類型參數能夠以引用類型傳遞,我們在第9章介紹過使用inout聲明的輸入輸出類型參數,這裏需要修改一下代碼:
func updateDept (inout dept : Department) {
dept.name = "Research"
}
println("Department更新前:\(dept.name)")
updateDept(&dept)
println("Department更新後:\(dept.name)")
我們不僅要將參數聲明為inout,而且要在使用實例前加上&符號。這樣修改後輸出結果如下:
Department更新前:Sales
Department更新後:Research
相比之下,第⑩行代碼是定義updateEmp函數,它的參數是Employee類的實例,我們不需要將參數聲明為inout類型。在第⑪行修改emp沒有編譯錯誤,這說明Employee類是引用類型,在調用的時候不用在變量前麵添加&符號,見代碼第 行。輸出結果如下:
Employee更新前:Salesman
Employee更新後:Clerk
這個結果再次說明了類是引用類。
三、引用類型的比較
我們在第4章介紹了基本運算符,提到了恒等於(===)和不恒等於(!===)關係運算符。===用於比較兩個引用是否為同一個實例,!===則恰恰相反,它隻能用於引用類型,也就是類的實例。
下麵我們看一個示例:
var emp1 = Employee() ① emp1.no = 1000 emp1.name = "Martin" emp1.job = "Salesman" emp1.salary = 1250 var emp2 = Employee() ② emp2.no = 1000 emp2.name = "Martin" emp2.job = "Salesman" emp2.salary = 1250 if emp1 === emp2 ③ { println("emp1 === emp2") } if emp1 === emp1 ④ { println("emp1 === emp1") } var dept1 = Department() ⑤ dept1.no = 10 dept1.name = "Sales" var dept2 = Department() ⑥ dept2.no = 10 dept2.name = "Sales" if dept1 == dept2 //編譯失敗 ⑦ { println("dept1 === dept2") }
上述代碼第①行和第②行分別創建了emp1和emp2兩個Employee實例。在代碼第③行比較emp1和emp2兩個引用是否為一個實例。可以看到,比較結果為False,也就是emp1和emp2兩個引用不是一個實例,即便是它們內容完全一樣,結果也是False,而第④行的比較結果為True。如果我們采用==比較,結果會如何呢?代碼如下:
if emp1 == emp2
{
println("emp1 === emp2")
}
答案是有如下編譯錯誤。==比較要求兩個實例的類型(類、結構體、枚舉等)必須要在該類型中重寫==運算符,定義相等規則。同樣的錯誤也會發生在第⑦行代碼。
Playground execution failed: error: <REPL>:42:9: error: could not find an overload for '==' that accepts the supplied arguments
if emp1 == emp2
~~~~~^~~~~~~
代碼第⑤行和第⑥行分別創建了dept1和dept2兩個Department實例。在代碼第⑦行使用==比較dept1和dept2兩個值是否相等,不僅不能比較,而且還會發生編譯錯誤,這在上麵已經解釋過了。
如果我們采用恒等於===比較dept1和dept2,結果會如何呢?代碼如下:
if dept1 === dept2
{
println("dept1 === dept2")
}
我們發現會有編譯錯誤。===不能比較值類型,而Department結構體是值類型,因此不能使用===比較。
更多內容請關注國內第一本Swift圖書《Swift開發指南》
本書交流討論網站:https://www.51work6.com/swift.php
歡迎加入Swift技術討論群:362298485
歡迎關注智捷iOS課堂微信公共平台

最後更新:2017-04-03 05:40:08
上一篇:
【原】訓練自己的haar-like特征分類器並識別物體(3)
下一篇:
基於opencv的皮膚檢測
知識總結 ExtJs"入門"
Maven學習二之settings.xml修改
jdk1.5新特性4之自動裝箱和自動拆箱與享元模式
J2EE中getParameter與getAttribute以及EL表達式${requestScope}和${param[]}
碼棧開發手冊(五)---可視化方式開發(模塊詳解--流程)
jQuery Mobile的默認配置項詳解,jQuery Mobile的中文配置api,jQuery Mobile的配置說明,配置大全
對西部數據 My Passport Wireless 移動存儲進行 Linux 魔改
六招教你用Python構建好玩的深度學習應用
多線程
日期分割,做按時間統計時會用到