Swift結構體與類

在面向過程的編程語言(如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

  1. var dept = Department() ①  編程

  2. dept.no = 10  swift

  3. dept.name = "Sales"         ②  微信

  4.   

  5.   

  6. var emp = Employee()        ③  閉包

  7. emp.no = 1000  編程語言

  8. emp.name = "Martin"  函數

  9. emp.job = "Salesman"  測試

  10. emp.salary = 1250  網站

  11. emp.dept = dept             ④  

  12.   

  13.   

  14. func updateDept (dept : Department) {   ⑤  

  15.     dept.name = "Research"  ⑥  

  16. }  

  17.   

  18.   

  19. println("Department更新前:\(dept.name)")   ⑦  

  20. updateDept(dept)                ⑧  

  21. println("Department更新後:\(dept.name)")   ⑨  

  22.   

  23.   

  24. func updateEmp (emp : Employee) {   ⑩  

  25.     emp.job = "Clerk"       ⑪  

  26. }  

  27.   

  28.   

  29. println("Employee更新前:\(emp.job)")   ⑫  

  30. updateEmp(emp)              ⑬  

  31. 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

  1. var emp1 = Employee()       ①  

  2. emp1.no = 1000  

  3. emp1.name = "Martin"  

  4. emp1.job = "Salesman"  

  5. emp1.salary = 1250  

  6.   

  7.   

  8. var emp2 = Employee()       ②  

  9. emp2.no = 1000  

  10. emp2.name = "Martin"  

  11. emp2.job = "Salesman"  

  12. emp2.salary = 1250  

  13.   

  14.   

  15.   

  16.   

  17. if emp1 === emp2                ③  

  18. {  

  19.     println("emp1 === emp2")  

  20. }  

  21. if emp1 === emp1                ④  

  22. {  

  23.     println("emp1 === emp1")  

  24. }  

  25.   

  26.   

  27. var dept1 = Department()    ⑤  

  28. dept1.no = 10  

  29. dept1.name = "Sales"  

  30.   

  31.   

  32. var dept2 = Department()    ⑥  

  33. dept2.no = 10  

  34. dept2.name = "Sales"  

  35.   

  36.   

  37. if dept1 == dept2   //編譯失敗  ⑦  

  38. {  

  39.     println("dept1 === dept2")  

  40. }  



上述代碼第①行和第②行分別建立了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課堂微信公共平臺

相關文章
相關標籤/搜索