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語言中的指針類型,只不過不需要在引用類型變量或常量前面加星號(*)。
下面我們看一個示例:
上述代碼第①~②行創建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章介紹了基本運算符,提到了恒等于(===)和不恒等于(!===)關系運算符。===用于比較兩個引用是否為同一個實例,!===則恰恰相反,它只能用于引用類型,也就是類的實例。
下面我們看一個示例:
上述代碼第①行和第②行分別創建了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課堂微信公共平臺
轉載于:https://www.cnblogs.com/iOS-Blog/p/3946812.html
總結
以上是生活随笔為你收集整理的Swift结构体与类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vitamio打造自己的Android万
- 下一篇: 9月1日收获