在面向過程的編程語言(如C語言)中,結構體用得比較多,可是面向對象以後,如在C++和Objective-C中,結構體已經不多使用了。這是由於結構體可以作的事情,類徹底能夠取而代之。
而Swift語言卻很是重視結構體,把結構體做爲實現面向對象的重要手段。Swift中的結構體與C++和Objective-C中的結構體有很大的差異,C++和Objective-C中的結構體只能定義一組相關的成員變量,而Swift中的結構體不只能夠定義成員變量(屬性),還能夠定義成員方法。所以,咱們能夠把結構體看作是一種輕量級的類。
Swift中的類和結構體很是相似,都具備定義和使用屬性、方法、下標和構造器等面向對象特性,可是結構體不具備繼承性,也不具有運行時強制類型轉換、使用析構器和使用引用計等能力。
1、類和結構體定義
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被稱爲「實例」,但只有類實例化的「實例」才能被稱爲「對象」。事實上,不只僅是結構體和類能夠實例化,枚舉、函數類型和閉包開闢內存空間的過程也能夠稱爲實例化,結果也能夠叫「實例」,但不能叫「對象」。
2、再談值類型和引用類型
數據類型能夠分爲:值類型和引用類型,這是由賦值或參數傳遞方式決定的。值類型就是在賦值或給函數傳遞參數時候,建立一個副本,把副本傳遞過去,這樣在函數的調用過程當中不會影響原始數據。引用類型就是在賦值或給函數傳遞參數的時候,把自己數據傳遞過去,這樣在函數的調用過程當中會影響原始數據。
在衆多的數據類型中,咱們只需記住:只有類是引用類型,其餘類型所有是值類型。即使結構體與類很是類似,它也是值類型。值類型還包括整型、浮點型、布爾型、字符串、元組、集合和枚舉。
Swift中的引用類型與Java中的引用類型是同樣的,Java中的類也是引用類型。若是你沒有Java經驗,能夠把引用類型理解爲C、C++和Objective-C語言中的指針類型,只不過不須要在引用類型變量或常量前面加星號(*)。
下面咱們看一個示例:
php
[html] view plaincopyhtml
var dept = Department() ① 編程
dept.no = 10 swift
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
這個結果再次說明了類是引用類。
3、引用類型的比較
咱們在第4章介紹了基本運算符,提到了恆等於(===)和不恆等於(!===)關係運算符。===用於比較兩個引用是否爲同一個實例,!===則偏偏相反,它只能用於引用類型,也就是類的實例。
下面咱們看一個示例:
[html] view plaincopy
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開發指南》
本書交流討論網站:http://www.51work6.com/swift.php
歡迎加入Swift技術討論羣:362298485
歡迎關注智捷iOS課堂微信公共平臺