Swift Tips - 結(jié)構(gòu)體(Struct) & 類(Class)

事實上,結(jié)構(gòu)體 & 我們并不是很陌生,在我們各種熟悉語言中均是存在,比如,C、C++、OC等。

前面我們已經(jīng)知道 Swift枚舉 著實豐富了很多,具體可以參見這篇文章。

而對于 結(jié)構(gòu)體 , Swift 也是對其寵愛有加。

有句話是這么說的來著:Swift 中,能用 結(jié)構(gòu)體 就不要用 ,除非需要 的那些特有的特性。

那么, Swift 中怎么定義 結(jié)構(gòu)體 呢?

什么是 結(jié)構(gòu)體 & ?

結(jié)構(gòu)體 & 類 是一種用于構(gòu)建程序代碼塊的靈活的穩(wěn)定的結(jié)構(gòu)??梢允褂门c定義常量,變量函數(shù) 相同的語法來定義 屬性方法 ,以向 結(jié)構(gòu)體 添加功能。(來自官網(wǎng)的翻譯)

誠如你所見,看似還是這么熟悉,卻又有一點不尋常,是的,我們可以向 結(jié)構(gòu)體 中添加 屬性&方法 ,就跟向 里面添加一樣一樣的!

所以,在 Swift結(jié)構(gòu)體 已經(jīng)擴展到跟 灰常神似的地步。

那么問題來了,這兩者到底還有什么區(qū)別呢?

異同 In 結(jié)構(gòu)體 & ?

Swift結(jié)構(gòu)體 的共同處在于:

  • 定義屬性用于存儲值

  • 定義方法用于提供功能

  • 定義下標(biāo)腳本用于訪問值

  • 定義構(gòu)造器用于生成初始化值

  • 通過擴展以增加默認(rèn)實現(xiàn)的功能

  • 實現(xiàn)協(xié)議以提供某種標(biāo)準(zhǔn)功能

Swift結(jié)構(gòu)體 的不同處在于:

  • 結(jié)構(gòu)體不具有繼承性

  • 結(jié)構(gòu)體不具備運行時強制類型轉(zhuǎn)換

  • 結(jié)構(gòu)體不具備使用析構(gòu)器的能力

  • 結(jié)構(gòu)體不具備使用引用計數(shù)的能力

綜上所述,如果我們需要構(gòu)建的代碼塊,只是需要 共同處 就能滿足,那么我們就選擇 結(jié)構(gòu)體 ;要是還需要 不同處 的特有功能,再選擇 。

語法

枚舉、結(jié)構(gòu)體、 的語法非常類似,分別使用 enum、struct、class關(guān)鍵字來定義:

struct SomeStructure {
 // structure definition goes here
}
class SomeClass {
 // class definition goes here
}

舉個栗子:

//用于描述基于像素的顯示分辨率。此結(jié)構(gòu)有兩個存儲的屬性,稱為width和height。
struct Resolution {
 var width = 0
 var height = 0
}
?
//用于描述視頻顯示的特定視頻模式。
class VideoMode {
 var resolution = Resolution()
 var interlaced = false
 var frameRate = 0.0
 var name: String?
}

可以像下面這樣創(chuàng)建實例,以及訪問:

let someResolution = Resolution()
let someVideoMode = VideoMode()
?
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0"
?
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"

這里需要了解的是,所有 結(jié)構(gòu)體 都有一個自動生成的成員初始化程序,可以使用它初始化新結(jié)構(gòu)實例的成員屬性:

let vga = Resolution(width: 640, height: 480)

而,類實例不接收默認(rèn)的成員初始值設(shè)定項。

其實,枚舉&結(jié)構(gòu)體 之間有一個很本質(zhì)的區(qū)別在于:枚舉&結(jié)構(gòu)體值類型,而 引用類型。

枚舉&結(jié)構(gòu)體 是 值類型

首先,什么是 值類型 ?

值類型 是一種最簡單的類型,為什么這么說了?因為常見,比如各種語言里面的Int、Float、Double之流都是。

進(jìn)一步可以理解為 值類型 是一種沒有指針概念的類型。

那么問題來了,何為沒有指針概念呢?

從存儲上看可以這么理解:值類型 都是存放在 中,而與之對應(yīng)的 引用類型 是在 中存儲 指針,數(shù)據(jù)存在 中,且棧中的指針指向?qū)?yīng)的數(shù)據(jù)的堆地址。

值得一說的是,Swift 中出了 枚舉、結(jié)構(gòu)體 是值類型,甚至連String,Array 以及 Dictionary 等都是值類型的。

為什么呢?因為 StringArray 以及 Dictionary其實都是通過 結(jié)構(gòu)體 實現(xiàn)的。

下面舉個栗子:

//實例化
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
//修改 width
cinema.width = 2048
?
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide"
?
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide"

當(dāng)cinema給出當(dāng)前值時hd,存儲的hd被復(fù)制到新cinema實例中。最終結(jié)果是兩個完全獨立的實例,它們包含相同的數(shù)值。但是,因為它們是單獨的實例,所以設(shè)置寬度cinemato 2048不會影響存儲的寬度hd,內(nèi)存情況如下圖所示:

內(nèi)存示意圖

類 是 引用類型

引用類型,與值類型不同,引用類型 在分配給變量或常量時或者傳遞給函數(shù)時其值不會被復(fù)制。而不是副本,使用對同一現(xiàn)有實例的引用。

其實就是所謂的 淺拷貝 :只復(fù)制指針,而不復(fù)制其值;

換一種說法就是,淺拷貝 只是復(fù)制棧內(nèi)存,而指向同一塊兒堆內(nèi)存。

還是舉個栗子直觀的理解一下:

//實例化,VideoMode是上面定義的類,hd是上面實例化的實例
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
?
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0"

內(nèi)存如下圖所示:


內(nèi)存示意圖

需要注意的是,tenEighty 并將 alsoTenEighty 其聲明為常量,而不是 變量。

但是,您仍然可以更改 tenEighty.frameRate,alsoTenEighty.frameRate,因為 tenEightyalsoTenEighty 本身(棧中的指針)并未更改。tenEighty 并且 alsoTenEighty 他們自己不“存儲”VideoMode實例 ( VideoMode實例存儲在堆中)。

那么又一個來了, 既然是引用類型,怎么判斷兩個實例是不是同一個呢?也就是說兩個不同的指針是不是指向同一塊堆內(nèi)存呢?

Swift 提供了一組操作符來方便的解決這個問題:===!== 。

看著就很好理解舉個栗子:

if tenEighty === alsoTenEighty {
 print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."

以上。

喜歡我的可以關(guān)注收藏我的個人博客:Ro.bber

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容