- 訪問控制可以限定其它源文件或模塊中的代碼對你的代碼的訪問級別。
- 這個特性可以讓我們隱藏代碼的一些實現(xiàn)細(xì)節(jié),并且可以為其他人可以訪問和使用的代碼提供接口。
- 可以明確地給單個類型(類、結(jié)構(gòu)體、枚舉)設(shè)置訪問級別,也可以給這些類型的屬性、方法、構(gòu)造器、下標(biāo)等設(shè)置訪問級別。
- 協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。
1. 模塊和源文件
- Swift 中的訪問控制模型基于模塊和源文件這兩個概念。
- 模塊指的是獨立的代碼單元,框架或應(yīng)用程序會作為一個獨立的模塊來構(gòu)建和發(fā)布。在 Swift 中,一個模塊可以使用 import 關(guān)鍵字導(dǎo)入另外一個模塊。
- 在 Swift 中,Xcode 的每個 target(例如框架或應(yīng)用程序)都被當(dāng)作獨立的模塊處理。如果你是為了實現(xiàn)某個通用的功能,或者是為了封裝一些常用方法而將代碼打包成獨立的框架,這個框架就是 Swift 中的一個模塊。當(dāng)它被導(dǎo)入到某個應(yīng)用程序或者其他框架時,框架內(nèi)容都將屬于這個獨立的模塊。
- 源文件就是 Swift 中的源代碼文件,它通常屬于一個模塊,即一個應(yīng)用程序或者框架。盡管我們一般會將不同的類型分別定義在不同的源文件中,但是同一個源文件也可以包含多個類型、函數(shù)之類的定義。
2. 訪問級別
Swift 為代碼中的實體提供了五種不同的訪問級別。這些訪問級別不僅與源文件中定義的實體相關(guān),同時也與源文件所屬的模塊相關(guān)。
-
Open 和 Public 級別可以讓實體被同一模塊源文件中的所有實體訪問,在模塊外也可以通過導(dǎo)入該模塊來訪問源文件里的所有實體。
- 通常情況下,你會使用 Open 或 Public 級別來指定框架的外部接口。
-
Internal 級別讓實體被同一模塊源文件中的任何實體訪問,但是不能被模塊外的實體訪問。
- 通常情況下,如果某個接口只在應(yīng)用程序或框架內(nèi)部使用,就可以將其設(shè)置為 Internal 級別。
-
File-private 限制實體只能在其定義的文件內(nèi)部訪問。
- 如果功能的部分細(xì)節(jié)只需要在文件內(nèi)使用時,可以使用 File-private 來將其隱藏。
-
Private 限制實體只能在其定義的作用域,以及同一文件內(nèi)的 extension 訪問。
- 如果功能的部分細(xì)節(jié)只需要在當(dāng)前作用域內(nèi)使用時,可以使用 Private 來將其隱藏。
Open 為最高訪問級別(限制最少),Private 為最低訪問級別(限制最多)。
-
Open 只能作用于類和類的成員,它和 Public 的區(qū)別如下:
- Public 或者其它更嚴(yán)訪問級別的類,只能在其定義的模塊內(nèi)部被繼承。
- Public 或者其它更嚴(yán)訪問級別的類成員,只能在其定義的模塊內(nèi)部的子類中重寫。
- Open 的類,可以在其定義的模塊中被繼承,也可以在引用它的模塊中被繼承。
- Open 的類成員,可以在其定義的模塊中子類中重寫,也可以在引用它的模塊中的子類重寫。
把一個類標(biāo)記為 open,明確的表示你已經(jīng)充分考慮過外部模塊使用此類作為父類的影響,并且設(shè)計好了你的類的代碼了。
2.1 訪問級別基本原則
- Swift 中的訪問級別遵循一個基本原則:實體不能定義在具有更低訪問級別(更嚴(yán)格)的實體中。
- 例如:
- 一個 Public 的變量,其類型的訪問級別不能是 Internal,F(xiàn)ile-private 或是 Private。因為無法保證變量的類型在使用變量的地方也具有訪問權(quán)限。
- 函數(shù)的訪問級別不能高于它的參數(shù)類型和返回類型的訪問級別。因為這樣就會出現(xiàn)函數(shù)可以在任何地方被訪問,但是它的參數(shù)類型和返回類型卻不可以的情況。
2.2 默認(rèn)訪問級別
- 如果你沒有為代碼中的實體顯式指定訪問級別,那么它們默認(rèn)為 internal 級別(有一些例外情況,稍后會進行說明)。
- 因此,在大多數(shù)情況下,我們不需要顯式指定實體的訪問級別。
2.3 單 target 應(yīng)用程序的訪問級別
- 當(dāng)你編寫一個單目標(biāo)應(yīng)用程序時,應(yīng)用的所有功能都是為該應(yīng)用服務(wù),而不需要提供給其他應(yīng)用或者模塊使用,所以我們不需要明確設(shè)置訪問級別,使用默認(rèn)的訪問級別 Internal 即可。
- 但是,你也可以使用 fileprivate 訪問或 private 訪問級別,用于隱藏一些功能的實現(xiàn)細(xì)節(jié)。
2.4 框架的訪問級別
當(dāng)你開發(fā)框架時,就需要把一些對外的接口定義為 Open 或 Public,以便使用者導(dǎo)入該框架后可以正常使用其功能。
-
這些被你定義為對外的接口,就是這個框架的 API。
注意 1. 框架的內(nèi)部實現(xiàn)仍然可以使用默認(rèn)的訪問級別 internal,當(dāng)你需要對框架內(nèi)部其它部分隱藏細(xì)節(jié)時可以使用 private 或 fileprivate。 2. 對于框架的對外 API 部分,你就需要將它們設(shè)置為 open 或 public 了。
2.5 單元測試 target 的訪問級別
- 當(dāng)你的應(yīng)用程序包含單元測試 target 時,為了測試,測試模塊需要訪問應(yīng)用程序模塊中的代碼。
- 默認(rèn)情況下只有 open 或 public 級別的實體才可以被其他模塊訪問。
- 然而,如果在導(dǎo)入應(yīng)用程序模塊的語句前使用 @testable 特性,然后在允許測試的編譯設(shè)置(Build Options -> Enable Testability)下編譯這個應(yīng)用程序模塊,單元測試目標(biāo)就可以訪問應(yīng)用程序模塊中所有內(nèi)部級別的實體。
3. 訪問控制語法
- 通過修飾符 open、public、internal、fileprivate、private 來聲明實體的訪問級別:
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
?
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}
- 除非專門指定,否則實體默認(rèn)的訪問級別為 internal,可以查閱 默認(rèn)訪問級別 這一節(jié)。
- 這意味著在不使用修飾符顯式聲明訪問級別的情況下,SomeInternalClass 和 someInternalConstant 仍然擁有隱式的 internal:
class SomeInternalClass {} // 隱式 internal
var someInternalConstant = 0 // 隱式 internal
4. 自定義類型
- 如果想為一個自定義類型指定訪問級別,在定義類型時進行指定即可。
- 新類型只能在它的訪問級別限制范圍內(nèi)使用。
- 例如,你定義了一個 fileprivate 級別的類,那這個類就只能在定義它的源文件中使用,可以作為屬性類型、函數(shù)參數(shù)類型或者返回類型,等等。
- 一個類型的訪問級別也會影響到類型成員(屬性、方法、構(gòu)造器、下標(biāo))的默認(rèn)訪問級別。
- 如果你將類型指定為 private 或者 fileprivate 級別,那么該類型的所有成員的默認(rèn)訪問級別也會變成 private 或者 fileprivate 級別。
- 如果你將類型指定為 internal 或 public(或者不明確指定訪問級別,而使用默認(rèn)的 internal ),那么該類型的所有成員的默認(rèn)訪問級別將是 internal。
重點:
上面提到,一個 public 類型的所有成員的訪問級別默認(rèn)為 internal 級別,而不是 public 級別。
如果你想將某個成員指定為 public 級別,那么你必須顯式指定。
這樣做的好處是,在你定義公共接口的時候,可以明確地選擇哪些接口是需要公開的,哪些是內(nèi)部使用的,避免不小心將內(nèi)部使用的接口公開。
public class SomePublicClass { // 顯式 public 類
public var somePublicProperty = 0 // 顯式 public 類成員
var someInternalProperty = 0 // 隱式 internal 類成員
fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
?
class SomeInternalClass { // 隱式 internal 類
var someInternalProperty = 0 // 隱式 internal 類成員
fileprivate func someFilePrivateMethod() {} // 顯式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
?
fileprivate class SomeFilePrivateClass { // 顯式 fileprivate 類
func someFilePrivateMethod() {} // 隱式 fileprivate 類成員
private func somePrivateMethod() {} // 顯式 private 類成員
}
?
private class SomePrivateClass { // 顯式 private 類
func somePrivateMethod() {} // 隱式 private 類成員
}
4.1 元組類型
元組的訪問級別將由元組中訪問級別最嚴(yán)格的類型來決定。
-
例如,如果你構(gòu)建了一個包含兩種不同類型的元組,其中一個類型為 internal,另一個類型為 private,那么這個元組的訪問級別為 private。
注意: 1. 元組不同于類、結(jié)構(gòu)體、枚舉、函數(shù)那樣有單獨的定義。 2. 元組的訪問級別是在它被使用時自動推斷出的,而無法明確指定。
4.2 函數(shù)類型
函數(shù)的訪問級別根據(jù)訪問級別最嚴(yán)格的參數(shù)類型或返回類型的訪問級別來決定。
但是,如果這種訪問級別不符合函數(shù)定義所在環(huán)境的默認(rèn)訪問級別,那么就需要明確地指定該函數(shù)的訪問級別。
下面的例子定義了一個名為 someFunction() 的全局函數(shù),并且沒有明確地指定其訪問級別。也許你會認(rèn)為該函數(shù)應(yīng)該擁有默認(rèn)的訪問級別 internal,但事實并非如此。事實上,如果按下面這種寫法,代碼將無法通過編譯:
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 此處是函數(shù)實現(xiàn)部分
}
我們可以看到,這個函數(shù)的返回類型是一個元組,該元組中包含兩個自定義的類(可查閱 自定義類型)。
其中一個類的訪問級別是 internal
另一個的訪問級別是 private所以根據(jù)元組訪問級別的原則,該元組的訪問級別是 private(元組的訪問級別與元組中訪問級別最低的類型一致)。
- 因為該函數(shù)返回類型的訪問級別是 private,所以你必須使用 private 修飾符,明確指定該函數(shù)的訪問級別:
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// 此處是函數(shù)實現(xiàn)部分
}
將該函數(shù)指定為 public 或 internal,或者使用默認(rèn)的訪問級別 internal 都是錯誤的,因為如果把該函數(shù)當(dāng)做 public 或 internal 級別來使用的話,可能會無法訪問 private 級別的返回值。
4.3 枚舉類型
- 枚舉成員的訪問級別和該枚舉類型相同,你不能為枚舉成員單獨指定不同的訪問級別。
- 比如下面的例子,枚舉 CompassPoint 被明確指定為 public,那么它的成員 North、South、East、West 的訪問級別同樣也是 public:
public enum CompassPoint {
case north
case south
case east
case west
}
4.4 原始值和關(guān)聯(lián)值
- 枚舉定義中的任何原始值或關(guān)聯(lián)值的類型的訪問級別至少不能低于枚舉類型的訪問級別。
- 例如,你不能在一個 internal 的枚舉中定義 private 的原始值類型。
4.5 嵌套類型
- 如果在 private 的類型中定義嵌套類型,那么該嵌套類型就自動擁有 private 訪問級別。
- 如果在 public 或者 internal 級別的類型中定義嵌套類型,那么該嵌套類型自動擁有 internal 訪問級別。
- 如果想讓嵌套類型擁有 public 訪問級別,那么需要明確指定該嵌套類型的訪問級別。
5. 子類
-
子類的訪問級別不得高于父類的訪問級別。
- 例如,父類的訪問級別是 internal,子類的訪問級別就不能是 public。
此外,你可以在符合當(dāng)前訪問級別的條件下重寫任意類成員(方法、屬性、構(gòu)造器、下標(biāo)等)。
可以通過重寫為繼承來的類成員提供更高的訪問級別。通過這種方式,我們就可以將某類中 fileprivate 級別的類成員重新指定為更高的訪問級別,以便其他人使用:
/*
類 A 的訪問級別是 public
它包含一個方法 someMethod()
訪問級別為 fileprivate
*/
public class A {
fileprivate func someMethod() {}
}
?
/*
類 B 繼承自類 A,訪問級別為 internal
但是在類 B 中重寫了類 A 中訪問級別為 fileprivate 的方法 someMethod()
并重新指定為 internal 級別
*/
internal class B: A {
override internal func someMethod() {}
}
- 我們甚至可以在子類中,用子類成員去訪問訪問級別更低的父類成員,只要這一操作在相應(yīng)訪問級別的限制范圍內(nèi)(也就是說,在同一源文件中訪問父類 fileprivate 級別的成員,在同一模塊內(nèi)訪問父類 internal 級別的成員):
public class A {
fileprivate func someMethod() {}
}
?
internal class B: A {
override internal func someMethod() {
super.someMethod()
}
}
因為父類 A 和子類 B 定義在同一個源文件中,所以在子類 B 可以在重寫的 someMethod() 方法中調(diào)用 super.someMethod()。
6. 常量、變量、屬性、下標(biāo)
- 常量、變量、屬性不能擁有比它們的類型更高的訪問級別。
- 例如,你不能定義一個 public 級別的屬性,但是它的類型卻是 private 級別的。同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問級別。
- 如果常量、變量、屬性、下標(biāo)的類型是 private 級別的,那么它們必須明確指定訪問級別為 private:
private var privateInstance = SomePrivateClass()
6.1 Getter 和 Setter
常量、變量、屬性、下標(biāo)的 Getters 和 Setters 的訪問級別和它們所屬類型的訪問級別相同。
Setter 的訪問級別可以低于對應(yīng)的 Getter 的訪問級別,這樣就可以控制變量、屬性或下標(biāo)的讀寫權(quán)限。
-
在 var 或 subscript 關(guān)鍵字之前,你可以通過 fileprivate(set),private(set) 或 internal(set) 為它們的寫入權(quán)限指定更低的訪問級別。
注意 1. 這個規(guī)則同時適用于存儲型屬性和計算型屬性。 2. 即使你不明確指定存儲型屬性的 Getter 和 Setter,Swift 也會隱式地為其創(chuàng)建 Getter 和 Setter,用于訪問該屬性的后備存儲。使用 fileprivate(set),private(set) 和 internal(set) 可以改變 Setter 的訪問級別,這對計算型屬性也同樣適用。 下面的例子中定義了一個名為 TrackedString 的結(jié)構(gòu)體,它記錄了 value 屬性被修改的次數(shù):
struct TrackedString {
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
TrackedString 結(jié)構(gòu)體定義了一個用于存儲 String 值的屬性 value,并將初始值設(shè)為 ""(一個空字符串)。
該結(jié)構(gòu)體還定義了另一個用于存儲 Int 值的屬性 numberOfEdits,它用于記錄屬性 value 被修改的次數(shù)。
這個功能通過屬性 value 的 didSet 觀察器實現(xiàn),每當(dāng)給 value 賦新值時就會調(diào)用 didSet 方法,然后將 numberOfEdits 的值加一。
結(jié)構(gòu)體 TrackedString 和它的屬性 value 都沒有顯式地指定訪問級別,所以它們都是用默認(rèn)的訪問級別 internal。
但是該結(jié)構(gòu)體的 numberOfEdits 屬性使用了 private(set) 修飾符,這意味著 numberOfEdits 屬性只能在結(jié)構(gòu)體的定義中進行賦值。
numberOfEdits 屬性的 Getter 依然是默認(rèn)的訪問級別 internal,但是 Setter 的訪問級別是 private,這表示該屬性只能在內(nèi)部修改,而在結(jié)構(gòu)體的外部則表現(xiàn)為一個只讀屬性。
- 如果你實例化 TrackedString 結(jié)構(gòu)體,并多次對 value 屬性的值進行修改,你就會看到 numberOfEdits 的值會隨著修改次數(shù)而變化:
var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
print("The number of edits is \(stringToEdit.numberOfEdits)")
// 打印“The number of edits is 3”
- 雖然你可以在其他的源文件中實例化該結(jié)構(gòu)體并且獲取到 numberOfEdits 屬性的值,但是你不能對其進行賦值。
- 這一限制保護了該記錄功能的實現(xiàn)細(xì)節(jié),同時還提供了方便的訪問方式。
- 你可以在必要時為 Getter 和 Setter 顯式指定訪問級別。
- 下面的例子將 TrackedString 結(jié)構(gòu)體明確指定為了 public 訪問級別。結(jié)構(gòu)體的成員(包括 numberOfEdits 屬性)擁有默認(rèn)的訪問級別 internal。你可以結(jié)合 public 和 private(set) 修飾符把結(jié)構(gòu)體中的 numberOfEdits 屬性的 Getter 的訪問級別設(shè)置為 public,而 Setter 的訪問級別設(shè)置為 private:
public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
7. 構(gòu)造器
- 自定義構(gòu)造器的訪問級別可以低于或等于其所屬類型的訪問級別。
- 唯一的例外是 必要構(gòu)造器,它的訪問級別必須和所屬類型的訪問級別相同。
- 如同函數(shù)或方法的參數(shù),構(gòu)造器參數(shù)的訪問級別也不能低于構(gòu)造器本身的訪問級別。
7.1 默認(rèn)構(gòu)造器
- Swift 會為結(jié)構(gòu)體和類提供一個默認(rèn)的無參數(shù)的構(gòu)造器,只要它們?yōu)樗写鎯π蛯傩栽O(shè)置了默認(rèn)初始值,并且未提供自定義的構(gòu)造器。
- 默認(rèn)構(gòu)造器的訪問級別與所屬類型的訪問級別相同,除非類型的訪問級別是 public。
- 如果一個類型被指定為 public 級別,那么默認(rèn)構(gòu)造器的訪問級別將為 internal。
- 如果你希望一個 public 級別的類型也能在其他模塊中使用這種無參數(shù)的默認(rèn)構(gòu)造器,你只能自己提供一個 public 訪問級別的無參數(shù)構(gòu)造器。
7.2 結(jié)構(gòu)體默認(rèn)的成員逐一構(gòu)造器
- 如果結(jié)構(gòu)體中任意存儲型屬性的訪問級別為 private,那么該結(jié)構(gòu)體默認(rèn)的成員逐一構(gòu)造器的訪問級別就是 private。
- 否則,這種構(gòu)造器的訪問級別依然是 internal。
- 如同前面提到的默認(rèn)構(gòu)造器,如果你希望一個 public 級別的結(jié)構(gòu)體也能在其他模塊中使用其默認(rèn)的成員逐一構(gòu)造器,你依然只能自己提供一個 public 訪問級別的成員逐一構(gòu)造器。
8. 協(xié)議
如果想為一個協(xié)議類型明確地指定訪問級別,在定義協(xié)議時指定即可。
這將限制該協(xié)議只能在適當(dāng)?shù)脑L問級別范圍內(nèi)被遵循。
協(xié)議中的每一個要求都具有和該協(xié)議相同的訪問級別。
-
你不能將協(xié)議中的要求設(shè)置為其他訪問級別。這樣才能確保該協(xié)議的所有要求對于任意遵循者都將可用。
注意 1. 如果你定義了一個 public 訪問級別的協(xié)議,那么該協(xié)議的所有實現(xiàn)也會是 public 訪問級別。 2. 這一點不同于其他類型,例如,當(dāng)類型是 public 訪問級別時,其成員的訪問級別卻只是 internal。
8.1 協(xié)議繼承
- 如果定義了一個繼承自其他協(xié)議的新協(xié)議,那么新協(xié)議擁有的訪問級別最高也只能和被繼承協(xié)議的訪問級別相同。
- 例如,你不能將繼承自 internal 協(xié)議的新協(xié)議定義為 public 協(xié)議。
8.2 協(xié)議遵循
一個類型可以遵循比它級別更低的協(xié)議。
例如,你可以定義一個 public 級別類型,它能在別的模塊中使用,但是如果它遵循一個 internal 協(xié)議,這個遵循的部分就只能在這個 internal 協(xié)議所在的模塊中使用。
遵循協(xié)議時的上下文級別是類型和協(xié)議中級別最小的那個。如果一個類型是 public 級別,但它要遵循的協(xié)議是 internal 級別,那么這個類型對該協(xié)議的遵循上下文就是 internal 級別。
當(dāng)你編寫或擴展一個類型讓它遵循一個協(xié)議時,你必須確保該類型對協(xié)議的每一個要求的實現(xiàn),至少與遵循協(xié)議的上下文級別一致。
-
例如,一個 public 類型遵循一個 internal 協(xié)議,這個類型對協(xié)議的所有實現(xiàn)至少都應(yīng)是 internal 級別的。
注意 Swift 和 Objective-C 一樣,協(xié)議遵循是全局的,也就是說,在同一程序中,一個類型不可能用兩種不同的方式實現(xiàn)同一個協(xié)議。
9. Extension
- Extension 可以在訪問級別允許的情況下對類、結(jié)構(gòu)體、枚舉進行擴展。
- Extension 的成員具有和原始類型成員一致的訪問級別。
- 例如,你使用 extension 擴展了一個 public 或者 internal 類型,extension 中的成員就默認(rèn)使用 internal 訪問級別,和原始類型中的成員一致。
- 如果你使用 extension 擴展了一個 private 類型,則 extension 的成員默認(rèn)使用 private 訪問級別。
- 或者,你可以明確指定 extension 的訪問級別(例如,private extension),從而給該 extension 中的所有成員指定一個新的默認(rèn)訪問級別。
- 這個新的默認(rèn)訪問級別仍然可以被單獨指定的訪問級別所覆蓋。
- 如果你使用 extension 來遵循協(xié)議的話,就不能顯式地聲明 extension 的訪問級別。
- extension 每個 protocol 要求的實現(xiàn)都默認(rèn)使用 protocol 的訪問級別。
9.1 Extension 的私有成員
- 擴展同一文件內(nèi)的類,結(jié)構(gòu)體或者枚舉,extension 里的代碼會表現(xiàn)得跟聲明在原類型里的一模一樣。也就是說你可以這樣:
- 在類型的聲明里聲明一個私有成員,在同一文件的 extension 里訪問。
- 在 extension 里聲明一個私有成員,在同一文件的另一個 extension 里訪問。
- 在 extension 里聲明一個私有成員,在同一文件的類型聲明里訪問。
- 這意味著你可以像組織的代碼去使用 extension,而且不受私有成員的影響。例如,給定下面這樣一個簡單的協(xié)議:
protocol SomeProtocol {
func doSomething()
}
- 你可以使用 extension 來遵循協(xié)議,就像這樣:
struct SomeStruct {
private var privateVariable = 12
}
?
extension SomeStruct: SomeProtocol {
func doSomething() {
print(privateVariable)
}
}
10. 泛型
- 泛型類型或泛型函數(shù)的訪問級別取決于泛型類型或泛型函數(shù)本身的訪問級別,還需結(jié)合類型參數(shù)的類型約束的訪問級別,根據(jù)這些訪問級別中的最低訪問級別來確定。
11. 類型別名
你定義的任何類型別名都會被當(dāng)作不同的類型,以便于進行訪問控制。
類型別名的訪問級別不可高于其表示的類型的訪問級別。
-
例如,private 級別的類型別名可以作為 private、file-private、internal、public 或者 open 類型的別名,但是 public 級別的類型別名只能作為 public 類型的別名,不能作為 internal、file-private 或 private 類型的別名。
注意:這條規(guī)則也適用于為滿足協(xié)議遵循而將類型別名用于關(guān)聯(lián)類型的情況。