//結(jié)構(gòu)和類
//結(jié)構(gòu)和類是通用的等龙、靈活的結(jié)構(gòu)处渣,它們成為程序代碼的代碼塊。
//您可以使用與定義常量蛛砰、變量和函數(shù)相同的語法來定義屬性和方法以向結(jié)構(gòu)和類添加功能罐栈。
//一、結(jié)構(gòu)和類的比較
//Swift 中的結(jié)構(gòu)和類有很多共同點(diǎn)泥畅。
//相同點(diǎn):
//定義存儲(chǔ)值的屬性
//定義提供功能的方法
//定義下標(biāo)以使用下表語法訪問它們的值
//定義初始值設(shè)定項(xiàng)以設(shè)置其初始狀態(tài)
//擴(kuò)展默認(rèn)實(shí)現(xiàn)之外的功能
//提供符合協(xié)議的標(biāo)準(zhǔn)功能
//另外荠诬,類還具有一些結(jié)構(gòu)不具備的功能:
//一個(gè)類可以繼承另外一個(gè)類特性的能力
//類型轉(zhuǎn)換使您能夠在運(yùn)行時(shí)檢查和解釋類的實(shí)例的類型
//析構(gòu)器使類的實(shí)例能夠釋放它分配的任何資源
//引用計(jì)數(shù)允許對(duì)一個(gè)類實(shí)例有多個(gè)引用
//1.定義語法
//結(jié)構(gòu)和類具有相似的定義語法。用struct關(guān)鍵字引入結(jié)構(gòu)位仁,用關(guān)鍵字class引入類柑贞。兩者都將整個(gè)定義放在一對(duì)大括號(hào)中:
struct SomeStructure {
// structure definition goes here
}
class SomeClass {
// class definition goes here
}
//備注:每當(dāng)你定義一個(gè)新的結(jié)構(gòu)或類時(shí),你就定義了一個(gè)新的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?
}
//上面的示例定義了一個(gè)名為Resolution的新結(jié)構(gòu)琳疏,用于描述基于像素的顯示分辨率有决。
//這個(gè)結(jié)構(gòu)有兩個(gè)存儲(chǔ)屬性,稱為width和height空盼。存儲(chǔ)屬性是常量或變量作為結(jié)構(gòu)或類的一部分捆綁在一起存儲(chǔ)的书幕。這兩個(gè)Int類型屬性的處事之為0。
//上面的示例還定義了一個(gè)名為VideoMode的新類揽趾,用于描述視頻顯示的特定視頻模式台汇。
//這個(gè)類有四個(gè)存儲(chǔ)變量屬性。第一個(gè) resolution用一個(gè)Resolution結(jié)構(gòu)實(shí)例初始化篱瞎,它推斷屬性類型為Resolution苟呐。
//其他三個(gè)屬性,VideoMode實(shí)例將屬性interlaced設(shè)置false俐筋、播放幀速率frameRate設(shè)置為0.0掠抬,name是一個(gè)可選String值來初始化,name屬性是一個(gè)可選類型自動(dòng)被賦予一個(gè)默認(rèn)值nil校哎。
//2.結(jié)構(gòu)和類實(shí)例
//創(chuàng)建實(shí)例的語法對(duì)于結(jié)構(gòu)和類都非常相似:
let someResolution = Resolution()
let someVideoMode = VideoMode()
//3.訪問屬性
//您可以使用點(diǎn)語法訪問實(shí)例的屬性两波。在點(diǎn)語法中瞳步,您在實(shí)例名稱后立即寫入屬性名稱,用句點(diǎn)(.)分隔腰奋,不帶任何空格:
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0"
//在本例中单起,someResolution.width引用someResolution的width屬性,并返回其默認(rèn)初始值0劣坊。
//您可以深入到子屬性嘀倒,例如VideoMode的resolution屬性的resolution屬性中的width屬性:
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is 0"
//您還可以使用點(diǎn)語法為變量屬性分配新值:
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)都有一個(gè)聰明的、自動(dòng)生成的初始化器局冰,您可以使用它來初始化新結(jié)構(gòu)實(shí)例的成員屬性测蘑。新實(shí)例屬性的初始值可以按名稱傳遞給成員初始化器:
let vga = Resolution(width: 640, height: 480)
//與結(jié)構(gòu)不同,類實(shí)例不接收默認(rèn)的成員初始化器
//二康二、結(jié)構(gòu)和枚舉是值類型
//值類型是一個(gè)類型碳胳,當(dāng)它被分配給一個(gè)變量或常量,或者把它傳遞給一個(gè)函數(shù)作為參數(shù)時(shí)沫勿,它的值是被復(fù)制過去的挨约。
//在前面的章節(jié)中桐磁,您實(shí)際上已經(jīng)廣泛使用了值類型临扮。
//事實(shí)上,Swift中的所有基本類型——整數(shù)桩了、浮點(diǎn)數(shù)蔓挖、布爾值夕土、字符串、數(shù)組和字典都是值類型瘟判,它們是以結(jié)構(gòu)的方式被實(shí)現(xiàn)怨绣。
//Swift中所有結(jié)構(gòu)和枚舉都是值類型。這意味著你創(chuàng)建的任何結(jié)構(gòu)和枚舉實(shí)例荒适,以及它們作為屬性的任何值類型梨熙,在你的代碼中傳遞時(shí)都會(huì)被復(fù)制开镣。
//備注:
//標(biāo)準(zhǔn)庫定義的集合(如數(shù)組刀诬、字典和字符串)使用優(yōu)化來降低復(fù)制的性能成本。
//這些集合不是立即復(fù)制邪财,而是在原始實(shí)例和任何副本之間共享存儲(chǔ)元素的內(nèi)存陕壹。
//如果集合的其中一個(gè)副本被修改,則元素將在修改之前復(fù)制树埠。您在代碼中看到的行為好像立即復(fù)制了一副新副本
//下面這個(gè)例子糠馆,它使用了上一個(gè)例子中的Resolution結(jié)構(gòu):
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
//此示例聲明了一個(gè)名為hd的常量,并將其設(shè)置為Resolution實(shí)例怎憋,初始化為使用全高清視頻的寬度和高度(1920 像素寬 x 1080 像素高)
//然后它聲明一個(gè)變量cinema又碌,并將其設(shè)置為hd的當(dāng)前值九昧。
//因?yàn)镽esolution是一個(gè)結(jié)構(gòu),當(dāng)把它分配給cinema的時(shí)候毕匀,根據(jù)現(xiàn)有實(shí)例的復(fù)制了一份副本并分配給cinema铸鹰。
//雖然hd和cinema現(xiàn)在有相同的寬度和高度,但是它們是兩種完全不同的實(shí)例
//接下來皂岔,將cinema的width屬性修改為用于數(shù)字電影放映的稍寬的2K標(biāo)準(zhǔn)的寬(2048 像素寬蹋笼,1080 像素高):
cinema.width = 2048
//檢查cinema的width屬性顯示它確實(shí)已更改為2048:
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide"
//但是,原始hd實(shí)例的width屬性仍然是舊值1920:
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide"
//當(dāng)cinema被賦予hd的當(dāng)前值時(shí)躁垛,存儲(chǔ)在hd的值被復(fù)制到新cinema實(shí)例中剖毯。
//最終結(jié)果是兩個(gè)完全獨(dú)立的實(shí)例包含相同數(shù)值的。但是教馆,由于它們是獨(dú)立的實(shí)例逊谋,因此設(shè)置cinema的值為2048的寬度,不會(huì)影響hd中存儲(chǔ)的寬度
//枚舉中的情況同樣是這樣:
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的值時(shí)活玲,它實(shí)際上復(fù)制了一份該值的副本涣狗。
//當(dāng)更改currentDirection的值后,不會(huì)影響存儲(chǔ)在rememberedDirection的值
//三舒憾、類是引用類型
//不同于值類型镀钓,當(dāng)引用類型分配給常量或變量,或者傳遞給函數(shù)的是镀迂,它不會(huì)復(fù)制一份副本丁溅,而使用同一個(gè)已經(jīng)存在的實(shí)例的引用
//這是一個(gè)示例,使用上面定義的類VideoMode:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
//接下來探遵,tenEighty分配給一個(gè)alsoTenEighty常量窟赏,alsoTenEighty修改的幀速率:
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
//由于類是引用類型,tenEighty和alsoTenEighty實(shí)際上都指向同一個(gè)VideoMode實(shí)例箱季。實(shí)際上涯穷,它們只是同一個(gè)實(shí)例的兩個(gè)不同名稱
//檢查tenEighty的frameRate屬性表明它正確展示為VideoMode實(shí)例的新幀速率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的值
//因?yàn)閠enEighty和alsoTenEighty作為常量本身的值實(shí)際上并沒有改變掘殴。
//tenEighty和alsoTenEighty他們自己不“存儲(chǔ)”VideoMode實(shí)例——相反赚瘦,他們都引用VideoMode的實(shí)例。
//改變frameRate是改變VideoMode的屬性奏寨,而不是改變VideoMode的常量引用的值起意。
//1.身份運(yùn)算符
//因?yàn)轭愂且妙愋停远鄠€(gè)常量和變量可能在幕后引用同一個(gè)類的單個(gè)實(shí)例病瞳。
//注意:結(jié)構(gòu)和枚舉并非如此揽咕,因?yàn)樗鼈冊诜峙浣o常量或變量或傳遞給函數(shù)時(shí)總是會(huì)被復(fù)制悲酷。
//有時(shí),找出兩個(gè)常量或變量是否指向一個(gè)類的同一個(gè)實(shí)例會(huì)很有用亲善。為了實(shí)現(xiàn)這一點(diǎn)舔涎,Swift提供了兩個(gè)身份運(yùn)算符:
//等同于(===)
//不等同于(!==)
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
//請注意,相同于(由三個(gè)等號(hào)或===表示)并不意味著與等于(由兩個(gè)等號(hào)或==表示相同逗爹。
//相同于意味著兩個(gè)常量或變量類型引用的類實(shí)例完全相同亡嫌。等于意味著兩個(gè)實(shí)例在值上被視為相等或等效。