//結(jié)構(gòu)和類
//結(jié)構(gòu)和類是通用的、靈活的結(jié)構(gòu),它們成為程序代碼的代碼塊。
//您可以使用與定義常量、變量和函數(shù)相同的語法來定義屬性和方法以向結(jié)構(gòu)和類添加功能。
//一、結(jié)構(gòu)和類的比較
//Swift 中的結(jié)構(gòu)和類有很多共同點。
//相同點:
//定義存儲值的屬性
//定義提供功能的方法
//定義下標(biāo)以使用下表語法訪問它們的值
//定義初始值設(shè)定項以設(shè)置其初始狀態(tài)
//擴展默認實現(xiàn)之外的功能
//提供符合協(xié)議的標(biāo)準(zhǔn)功能
//另外,類還具有一些結(jié)構(gòu)不具備的功能:
//一個類可以繼承另外一個類特性的能力
//類型轉(zhuǎn)換使您能夠在運行時檢查和解釋類的實例的類型
//析構(gòu)器使類的實例能夠釋放它分配的任何資源
//引用計數(shù)允許對一個類實例有多個引用
//1.定義語法
//結(jié)構(gòu)和類具有相似的定義語法。用struct關(guān)鍵字引入結(jié)構(gòu),用關(guān)鍵字class引入類。兩者都將整個定義放在一對大括號中:
struct SomeStructure {
// structure definition goes here
}
class SomeClass {
// class definition goes here
}
//備注:每當(dāng)你定義一個新的結(jié)構(gòu)或類時,你就定義了一個新的Swift類型。
//使用大駝峰(UpperCamelCase)命名類型(例如SomeStructure和SomeClass)以匹配標(biāo)準(zhǔn)Swift類型(例如String, Int, 和Bool)的大小寫。
//使用小駝峰(lowerCamelCase)命名屬性和方法(例如frameRate和incrementCount)以將它們與類型名稱區(qū)分開來。
//這是結(jié)構(gòu)定義和類定義的示例:
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
//上面的示例定義了一個名為Resolution的新結(jié)構(gòu),用于描述基于像素的顯示分辨率。
//這個結(jié)構(gòu)有兩個存儲屬性,稱為width和height。存儲屬性是常量或變量作為結(jié)構(gòu)或類的一部分捆綁在一起存儲的。這兩個Int類型屬性的處事之為0。
//上面的示例還定義了一個名為VideoMode的新類,用于描述視頻顯示的特定視頻模式。
//這個類有四個存儲變量屬性。第一個 resolution用一個Resolution結(jié)構(gòu)實例初始化,它推斷屬性類型為Resolution。
//其他三個屬性,VideoMode實例將屬性interlaced設(shè)置false、播放幀速率frameRate設(shè)置為0.0,name是一個可選String值來初始化,name屬性是一個可選類型自動被賦予一個默認值nil。
//2.結(jié)構(gòu)和類實例
//創(chuàng)建實例的語法對于結(jié)構(gòu)和類都非常相似:
let someResolution = Resolution()
let someVideoMode = VideoMode()
//3.訪問屬性
//您可以使用點語法訪問實例的屬性。在點語法中,您在實例名稱后立即寫入屬性名稱,用句點(.)分隔,不帶任何空格:
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0"
//在本例中,someResolution.width引用someResolution的width屬性,并返回其默認初始值0。
//您可以深入到子屬性,例如VideoMode的resolution屬性的resolution屬性中的width屬性:
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is 0"
//您還可以使用點語法為變量屬性分配新值:
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is now 1280"
//4.結(jié)構(gòu)類型的成員初始化器
//所有結(jié)構(gòu)都有一個聰明的、自動生成的初始化器,您可以使用它來初始化新結(jié)構(gòu)實例的成員屬性。新實例屬性的初始值可以按名稱傳遞給成員初始化器:
let vga = Resolution(width: 640, height: 480)
//與結(jié)構(gòu)不同,類實例不接收默認的成員初始化器
//二、結(jié)構(gòu)和枚舉是值類型
//值類型是一個類型,當(dāng)它被分配給一個變量或常量,或者把它傳遞給一個函數(shù)作為參數(shù)時,它的值是被復(fù)制過去的。
//在前面的章節(jié)中,您實際上已經(jīng)廣泛使用了值類型。
//事實上,Swift中的所有基本類型——整數(shù)、浮點數(shù)、布爾值、字符串、數(shù)組和字典都是值類型,它們是以結(jié)構(gòu)的方式被實現(xiàn)。
//Swift中所有結(jié)構(gòu)和枚舉都是值類型。這意味著你創(chuàng)建的任何結(jié)構(gòu)和枚舉實例,以及它們作為屬性的任何值類型,在你的代碼中傳遞時都會被復(fù)制。
//備注:
//標(biāo)準(zhǔn)庫定義的集合(如數(shù)組、字典和字符串)使用優(yōu)化來降低復(fù)制的性能成本。
//這些集合不是立即復(fù)制,而是在原始實例和任何副本之間共享存儲元素的內(nèi)存。
//如果集合的其中一個副本被修改,則元素將在修改之前復(fù)制。您在代碼中看到的行為好像立即復(fù)制了一副新副本
//下面這個例子,它使用了上一個例子中的Resolution結(jié)構(gòu):
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
//此示例聲明了一個名為hd的常量,并將其設(shè)置為Resolution實例,初始化為使用全高清視頻的寬度和高度(1920 像素寬 x 1080 像素高)
//然后它聲明一個變量cinema,并將其設(shè)置為hd的當(dāng)前值。
//因為Resolution是一個結(jié)構(gòu),當(dāng)把它分配給cinema的時候,根據(jù)現(xiàn)有實例的復(fù)制了一份副本并分配給cinema。
//雖然hd和cinema現(xiàn)在有相同的寬度和高度,但是它們是兩種完全不同的實例
//接下來,將cinema的width屬性修改為用于數(shù)字電影放映的稍寬的2K標(biāo)準(zhǔn)的寬(2048 像素寬,1080 像素高):
cinema.width = 2048
//檢查cinema的width屬性顯示它確實已更改為2048:
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide"
//但是,原始hd實例的width屬性仍然是舊值1920:
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide"
//當(dāng)cinema被賦予hd的當(dāng)前值時,存儲在hd的值被復(fù)制到新cinema實例中。
//最終結(jié)果是兩個完全獨立的實例包含相同數(shù)值的。但是,由于它們是獨立的實例,因此設(shè)置cinema的值為2048的寬度,不會影響hd中存儲的寬度
//枚舉中的情況同樣是這樣:
enum CompassPoint {
case north, south, east, west
mutating func turnNorth() {
self = .north
}
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()
print("The current direction is \(currentDirection)")
print("The remembered direction is \(rememberedDirection)")
// Prints "The current direction is north"
// Prints "The remembered direction is west"
//當(dāng)rememberedDirection被分配為currentDirection的值時,它實際上復(fù)制了一份該值的副本。
//當(dāng)更改currentDirection的值后,不會影響存儲在rememberedDirection的值
//三、類是引用類型
//不同于值類型,當(dāng)引用類型分配給常量或變量,或者傳遞給函數(shù)的是,它不會復(fù)制一份副本,而使用同一個已經(jīng)存在的實例的引用
//這是一個示例,使用上面定義的類VideoMode:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
//接下來,tenEighty分配給一個alsoTenEighty常量,alsoTenEighty修改的幀速率:
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
//由于類是引用類型,tenEighty和alsoTenEighty實際上都指向同一個VideoMode實例。實際上,它們只是同一個實例的兩個不同名稱
//檢查tenEighty的frameRate屬性表明它正確展示為VideoMode實例的新幀速率30.0:
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0"
//請注意,tenEighty和alsoTenEighty被聲明為常量,而不是變量。但是,仍然可以更改tenEighty.frameRate和alsoTenEighty.frameRate的值
//因為tenEighty和alsoTenEighty作為常量本身的值實際上并沒有改變。
//tenEighty和alsoTenEighty他們自己不“存儲”VideoMode實例——相反,他們都引用VideoMode的實例。
//改變frameRate是改變VideoMode的屬性,而不是改變VideoMode的常量引用的值。
//1.身份運算符
//因為類是引用類型,所以多個常量和變量可能在幕后引用同一個類的單個實例。
//注意:結(jié)構(gòu)和枚舉并非如此,因為它們在分配給常量或變量或傳遞給函數(shù)時總是會被復(fù)制。
//有時,找出兩個常量或變量是否指向一個類的同一個實例會很有用。為了實現(xiàn)這一點,Swift提供了兩個身份運算符:
//等同于(===)
//不等同于(!==)
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
//請注意,相同于(由三個等號或===表示)并不意味著與等于(由兩個等號或==表示相同。
//相同于意味著兩個常量或變量類型引用的類實例完全相同。等于意味著兩個實例在值上被視為相等或等效。