[譯]最近正在參與的Swift2.0翻譯工作(Access Control章節(jié))

2018-06-19 15:09 更新

訪問(wèn)控制


本頁(yè)內(nèi)容包括:

訪問(wèn)控制可以限定其他源文件或模塊中代碼對(duì)你代碼的訪問(wèn)級(jí)別。這個(gè)特性可以讓我們隱藏功能實(shí)現(xiàn)的一些細(xì)節(jié),并且可以明確的申明我們提供給其他人的接口中哪些部分是他們可以訪問(wèn)和使用的。

你可以明確地給單個(gè)類型(類、結(jié)構(gòu)體、枚舉)設(shè)置訪問(wèn)級(jí)別,也可以給這些類型的屬性、函數(shù)、初始化方法、基本類型、下標(biāo)索引等設(shè)置訪問(wèn)級(jí)別。協(xié)議也可以被限定在一定的范圍內(nèi)使用,包括協(xié)議里的全局常量、變量和函數(shù)。

在提供了不同訪問(wèn)級(jí)別的同時(shí),Swift還為某些典型場(chǎng)景提供了默認(rèn)的訪問(wèn)級(jí)別,這樣就不需要我們?cè)诿慷未a中都申明顯式訪問(wèn)級(jí)別。其實(shí),如果只是開發(fā)一個(gè)單目標(biāo)應(yīng)用程序,我們完全可以不用申明代碼的顯式訪問(wèn)級(jí)別。

注意:簡(jiǎn)單起見(jiàn),代碼中可以設(shè)置訪問(wèn)級(jí)別的特性(屬性、基本類型、函數(shù)等),在下面的章節(jié)中我們會(huì)以“實(shí)體”代替。

<a name="modules_and_source_files"></a>

模塊和源文件

Swift 中的訪問(wèn)控制模型基于模塊和源文件這兩個(gè)概念。

模塊指的是以獨(dú)立單元構(gòu)建和發(fā)布的FrameworkApplication。在Swift 中的一個(gè)模塊可以使用import關(guān)鍵字引入另外一個(gè)模塊。

在 Swift 中,Xcode的每個(gè)構(gòu)建目標(biāo)(比如Frameworkapp bundle)都被當(dāng)作模塊處理。如果你是為了實(shí)現(xiàn)某個(gè)通用的功能,或者是為了封裝一些常用方法而將代碼打包成獨(dú)立的Framework,這個(gè)Framework在 Swift 中就被稱為模塊。當(dāng)它被引入到某個(gè) app 工程或者另外一個(gè)Framework時(shí),它里面的一切(屬性、函數(shù)等)仍然屬于這個(gè)獨(dú)立的模塊。

源文件指的是 Swift 中的Swift File,就是編寫 Swift 源代碼的文件,它通常屬于一個(gè)模塊。盡管一般我們將不同的 分別定義在不同的源文件中,但是同一個(gè)源文件可以包含多個(gè)函數(shù) 的定義。

<a name="access_levels"></a>

訪問(wèn)級(jí)別

Swift 為代碼中的實(shí)體提供了三種不同的訪問(wèn)級(jí)別。這些訪問(wèn)級(jí)別不僅與源文件中定義的實(shí)體相關(guān),同時(shí)也與源文件所屬的模塊相關(guān)。

  • public:可以訪問(wèn)自己模塊中源文件里的任何實(shí)體,別人也可以通過(guò)引入該模塊來(lái)訪問(wèn)源文件里的所有實(shí)體。通常情況下,Framework 中的某個(gè)接口是可以被任何人使用時(shí),你可以將其設(shè)置為public級(jí)別。
  • internal:可以訪問(wèn)自己模塊中源文件里的任何實(shí)體,但是別人不能訪問(wèn)該模塊中源文件里的實(shí)體。通常情況下,某個(gè)接口或Framework作為內(nèi)部結(jié)構(gòu)使用時(shí),你可以將其設(shè)置為internal級(jí)別。
  • private:只能在當(dāng)前源文件中使用的實(shí)體,稱為私有實(shí)體。使用private級(jí)別,可以用作隱藏某些功能的實(shí)現(xiàn)細(xì)節(jié)。

public為最高級(jí)訪問(wèn)級(jí)別,private為最低級(jí)訪問(wèn)級(jí)別。

注意:Swift中的private訪問(wèn)和其他語(yǔ)言中的private訪問(wèn)不太一樣,它的范圍限于整個(gè)源文件,而不是聲明。這就意味著,一個(gè) 可以訪問(wèn)定義該 的源文件中定義的所有private實(shí)體,但是如果一個(gè) 的擴(kuò)展是定義在獨(dú)立的源文件中,那么就不能訪問(wèn)這個(gè)private成員。

<a name="guiding_principle_of_access_levels"></a>

訪問(wèn)級(jí)別的使用原則

Swift 中的訪問(wèn)級(jí)別遵循一個(gè)使用原則:訪問(wèn)級(jí)別統(tǒng)一性。 比如說(shuō):

  • 一個(gè)public訪問(wèn)級(jí)別的變量,不能將它的類型定義為internalprivate。因?yàn)樽兞靠梢员蝗魏稳嗽L問(wèn),但是定義它的類型不可以,所以這樣就會(huì)出現(xiàn)錯(cuò)誤。
  • 函數(shù)的訪問(wèn)級(jí)別不能高于它的參數(shù)、返回類型的訪問(wèn)級(jí)別。因?yàn)槿绻瘮?shù)定義為public而參數(shù)或者返回類型定義為internalprivate,就會(huì)出現(xiàn)函數(shù)可以被任何人訪問(wèn),但是它的參數(shù)和返回類型確不可以,同樣會(huì)出現(xiàn)錯(cuò)誤。

<a name="default_access_levels"></a>

默認(rèn)訪問(wèn)級(jí)別

如果你不為代碼中的所有實(shí)體定義顯式訪問(wèn)級(jí)別,那么它們默認(rèn)為internal級(jí)別。在大多數(shù)情況下,我們不需要設(shè)置實(shí)體的顯式訪問(wèn)級(jí)別。因?yàn)槲覀円话愣际窃陂_發(fā)一個(gè)app bundle。

<a name="access_levels_for_single-target_apps"></a>

單目標(biāo)應(yīng)用程序的訪問(wèn)級(jí)別

當(dāng)你編寫一個(gè)單目標(biāo)應(yīng)用程序時(shí),該應(yīng)用的所有功能都是為該應(yīng)用服務(wù),不需要提供給其他應(yīng)用或者模塊使用,所以我們不需要明確設(shè)置訪問(wèn)級(jí)別,使用默認(rèn)的訪問(wèn)級(jí)別internal即可。但是如果你愿意,你也可以使用private級(jí)別,用于隱藏一些功能的實(shí)現(xiàn)細(xì)節(jié)。

<a name="access_levels_for_frameworks"></a>

Framework的訪問(wèn)級(jí)別

當(dāng)你開發(fā)Framework時(shí),就需要把一些對(duì)外的接口定義為public級(jí)別,以便其他人導(dǎo)入該Framework后可以正常使用其功能。這些被你定義為public的接口,就是這個(gè)Framework的API。

注意:Framework的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)依然可以使用默認(rèn)的internal級(jí)別,或者也可以定義為private級(jí)別。只有當(dāng)你想把它作為 API 的一部分的時(shí)候,才將其定義為public級(jí)別。

<a name="access_levels_for_unit_test_targets"></a>

單元測(cè)試目標(biāo)的訪問(wèn)級(jí)別

當(dāng)你的app有單元測(cè)試目標(biāo)時(shí),為了方便測(cè)試,測(cè)試模塊需要能訪問(wèn)到你app中的代碼。默認(rèn)情況下只有public級(jí)別的實(shí)體才可以被其他模塊訪問(wèn)。然而,如果在引入一個(gè)生產(chǎn)模塊時(shí)使用@testable注解,然后用帶測(cè)試的方式編譯這個(gè)生產(chǎn)模塊,單元測(cè)試目標(biāo)就可以訪問(wèn)所有internal級(jí)別的實(shí)體。

<a name="access_control_syntax"></a>

訪問(wèn)控制語(yǔ)法

通過(guò)修飾符public、internal、private來(lái)聲明實(shí)體的訪問(wèn)級(jí)別:

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}


public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

除非有特殊的說(shuō)明,否則實(shí)體都使用默認(rèn)的訪問(wèn)級(jí)別internal,可以查閱默認(rèn)訪問(wèn)級(jí)別這一節(jié)。這意味著在不使用修飾符聲明顯式訪問(wèn)級(jí)別的情況下,SomeInternalClasssomeInternalConstant仍然擁有隱式的訪問(wèn)級(jí)別internal

class SomeInternalClass {}              // 隱式訪問(wèn)級(jí)別 internal
var someInternalConstant = 0            // 隱式訪問(wèn)級(jí)別 internal

<a name="custom_types"></a>

自定義類型

如果想為一個(gè)自定義類型申明顯式訪問(wèn)級(jí)別,那么要明確一點(diǎn)。那就是你要確保新類型的訪問(wèn)級(jí)別和它實(shí)際的作用域相匹配。比如說(shuō),如果你定義了一個(gè)private類,那這個(gè)類就只能在定義它的源文件中當(dāng)作屬性類型、函數(shù)參數(shù)或者返回類型使用。

類的訪問(wèn)級(jí)別也可以影響到類成員(屬性、函數(shù)、初始化方法等)的默認(rèn)訪問(wèn)級(jí)別。如果你將類申明為private類,那么該類的所有成員的默認(rèn)訪問(wèn)級(jí)別也會(huì)成為private。如果你將類申明為public或者internal類(或者不明確的申明訪問(wèn)級(jí)別,而使用默認(rèn)的internal訪問(wèn)級(jí)別),那么該類的所有成員的訪問(wèn)級(jí)別是internal。

注意:上面提到,一個(gè)public類的所有成員的訪問(wèn)級(jí)別默認(rèn)為internal級(jí)別,而不是public級(jí)別。如果你想將某個(gè)成員申明為public級(jí)別,那么你必須使用修飾符明確的聲明該成員。這樣做的好處是,在你定義公共接口API的時(shí)候,可以明確的選擇哪些屬性或方法是需要公開的,哪些是內(nèi)部使用的,可以避免將內(nèi)部使用的屬性方法公開成公共API的錯(cuò)誤。

public class SomePublicClass {          // 顯式的 public 類
    public var somePublicProperty = 0    // 顯式的 public 類成員
    var someInternalProperty = 0         // 隱式的 internal 類成員
    private func somePrivateMethod() {}  // 顯式的 private 類成員
}


class SomeInternalClass {               // 隱式的 internal 類
    var someInternalProperty = 0         // 隱式的 internal 類成員
    private func somePrivateMethod() {}  // 顯式的 private 類成員
}


private class SomePrivateClass {        // 顯式的 private 類
    var somePrivateProperty = 0          // 隱式的 private 類成員
    func somePrivateMethod() {}          // 隱式的 private 類成員
}

<a name="tuple_types"></a>

元組類型

元組的訪問(wèn)級(jí)別使用是所有類型的訪問(wèn)級(jí)別使用中最為嚴(yán)謹(jǐn)?shù)摹1热缯f(shuō),如果你構(gòu)建一個(gè)包含兩種不同類型元素的元組,其中一個(gè)元素類型的訪問(wèn)級(jí)別為internal,另一個(gè)為private級(jí)別,那么這個(gè)元組的訪問(wèn)級(jí)別為private。也就是說(shuō)元組的訪問(wèn)級(jí)別與元組中訪問(wèn)級(jí)別最低的類型一致。

注意:元組不同于類、結(jié)構(gòu)體、枚舉、函數(shù)那樣有單獨(dú)的定義。元組的訪問(wèn)級(jí)別是在它被使用時(shí)自動(dòng)推導(dǎo)出的,而不是明確的申明。

<a name="function_types"></a>

函數(shù)類型

函數(shù)的訪問(wèn)級(jí)別需要根據(jù)該函數(shù)的參數(shù)類型和返回類型的訪問(wèn)級(jí)別得出。如果根據(jù)參數(shù)類型和返回類型得出的函數(shù)訪問(wèn)級(jí)別不符合默認(rèn)上下文,那么就需要明確地申明該函數(shù)的訪問(wèn)級(jí)別。

下面的例子定義了一個(gè)名為someFunction全局函數(shù),并且沒(méi)有明確地申明其訪問(wèn)級(jí)別。也許你會(huì)認(rèn)為該函數(shù)應(yīng)該擁有默認(rèn)的訪問(wèn)級(jí)別internal,但事實(shí)并非如此。事實(shí)上,如果按下面這種寫法,帶埋是無(wú)法編譯通過(guò)的:

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // function implementation goes here
}

我們可以看到,這個(gè)函數(shù)的返回類型是一個(gè)元組,該元組中包含兩個(gè)自定義的類(可查閱自定義類型)。其中一個(gè)類的訪問(wèn)級(jí)別是internal,另一個(gè)的訪問(wèn)級(jí)別是private,所以根據(jù)元組訪問(wèn)級(jí)別的原則,該元組的訪問(wèn)級(jí)別是private(元組的訪問(wèn)級(jí)別與元組中訪問(wèn)級(jí)別最低的類型一致)。

因?yàn)樵摵瘮?shù)返回類型的訪問(wèn)級(jí)別是private,所以你必須使用private修飾符,明確的聲明該函數(shù):

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // function implementation goes here
}

將該函數(shù)申明為publicinternal,或者使用默認(rèn)的訪問(wèn)級(jí)別internal都是錯(cuò)誤的,因?yàn)槿绻言摵瘮?shù)當(dāng)做publicinternal級(jí)別來(lái)使用的話,是無(wú)法得到private級(jí)別的返回值的。

<a name="enumeration_types"></a>

枚舉類型

枚舉中成員的訪問(wèn)級(jí)別繼承自該枚舉,你不能為枚舉中的成員單獨(dú)申明不同的訪問(wèn)級(jí)別。

比如下面的例子,枚舉CompassPoint被明確的申明為public級(jí)別,那么它的成員North,South,East,West的訪問(wèn)級(jí)別同樣也是public

public enum CompassPoint {
    case North
    case South
    case East
    case West
}

<a name="raw_values_and_associated_values"></a>

原始值和關(guān)聯(lián)值

枚舉定義中的任何原始值或關(guān)聯(lián)值的類型都必須有一個(gè)訪問(wèn)級(jí)別,這個(gè)級(jí)別至少要不低于枚舉的訪問(wèn)級(jí)別。比如說(shuō),你不能在一個(gè)internal訪問(wèn)級(jí)別的枚舉中定義private級(jí)別的原始值類型。

<a name="nested_types"></a>

嵌套類型

如果在private級(jí)別的類型中定義嵌套類型,那么該嵌套類型就自動(dòng)擁有private訪問(wèn)級(jí)別。如果在public或者internal級(jí)別的類型中定義嵌套類型,那么該嵌套類型自動(dòng)擁有internal訪問(wèn)級(jí)別。如果想讓嵌套類型擁有public訪問(wèn)級(jí)別,那么需要明確地申明該嵌套類型的訪問(wèn)級(jí)別。

<a name="subclassing"></a>

子類

子類的訪問(wèn)級(jí)別不得高于父類的訪問(wèn)級(jí)別。比如說(shuō),父類的訪問(wèn)級(jí)別是internal,子類的訪問(wèn)級(jí)別就不能申明為public。

此外,在滿足子類不高于父類訪問(wèn)級(jí)別以及遵循各訪問(wèn)級(jí)別作用域(即模塊或源文件)的前提下,你可以重寫任意類成員(方法、屬性、初始化方法、下標(biāo)索引等)。

如果我們無(wú)法直接訪問(wèn)某個(gè)類中的屬性或函數(shù)等,那么可以繼承該類,從而可以更容易的訪問(wèn)到該類的類成員。下面的例子中,類A的訪問(wèn)級(jí)別是public,它包含一個(gè)函數(shù)someMethod,訪問(wèn)級(jí)別為private。類B繼承類A,并且訪問(wèn)級(jí)別申明為internal,但是在類B中重寫了類A中訪問(wèn)級(jí)別為private的方法someMethod,并重新申明為internal級(jí)別。通過(guò)這種方式,我們就可以訪問(wèn)到某類中private級(jí)別的類成員,并且可以重新申明其訪問(wèn)級(jí)別,以便其他人使用:

public class A {
    private func someMethod() {}
}


internal class B: A {
    override internal func someMethod() {}
}

只要滿足子類不高于父類訪問(wèn)級(jí)別以及遵循各訪問(wèn)級(jí)別作用域的前提下(即private的作用域在同一個(gè)源文件中,internal的作用域在同一個(gè)模塊下),我們甚至可以在子類中,用子類成員訪問(wèn)父類成員,哪怕父類成員的訪問(wèn)級(jí)別比子類成員的要低:

public class A {
    private func someMethod() {}
}


internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}

因?yàn)楦割?code>A和子類B定義在同一個(gè)源文件中,所以在類B中可以在重寫的someMethod方法中調(diào)用super.someMethod()。

<a name="constants_variables_properties_subscripts"></a>

常量、變量、屬性、下標(biāo)

常量、變量、屬性不能擁有比它們的類型更高的訪問(wèn)級(jí)別。比如說(shuō),你定義一個(gè)public級(jí)別的屬性,但是它的類型是private級(jí)別的,這是編譯器所不允許的。同樣,下標(biāo)也不能擁有比索引類型或返回類型更高的訪問(wèn)級(jí)別。

如果常量、變量、屬性、下標(biāo)索引的定義類型是private級(jí)別的,那么它們必須要明確的申明訪問(wèn)級(jí)別為private

private var privateInstance = SomePrivateClass()

<a name="getters_and_setters"></a>

Getter和Setter

常量、變量、屬性、下標(biāo)索引的GettersSetters的訪問(wèn)級(jí)別繼承自它們所屬成員的訪問(wèn)級(jí)別。

Setter的訪問(wèn)級(jí)別可以低于對(duì)應(yīng)的Getter的訪問(wèn)級(jí)別,這樣就可以控制變量、屬性或下標(biāo)索引的讀寫權(quán)限。在varsubscript定義作用域之前,你可以通過(guò)private(set)internal(set)先為它們的寫權(quán)限申明一個(gè)較低的訪問(wèn)級(jí)別。

注意:這個(gè)規(guī)定適用于用作存儲(chǔ)的屬性或用作計(jì)算的屬性。即使你不明確地申明存儲(chǔ)屬性的Getter、Setter,Swift也會(huì)隱式的為其創(chuàng)建GetterSetter,用于對(duì)該屬性進(jìn)行讀取操作。使用private(set)internal(set)可以改變Swift隱式創(chuàng)建的Setter的訪問(wèn)級(jí)別。這對(duì)計(jì)算屬性也同樣適用。

下面的例子中定義了一個(gè)名為TrackedString的結(jié)構(gòu)體,它記錄了value屬性被修改的次數(shù):

struct TrackedString {
    private(set) var numberOfEdits = 0
    var value: String = "" {
    didSet {
        numberOfEdits++
    }
    }
}

TrackedString結(jié)構(gòu)體定義了一個(gè)用于存儲(chǔ)String類型的屬性value,并將初始化值設(shè)為""(即一個(gè)空字符串)。該結(jié)構(gòu)體同時(shí)也定義了另一個(gè)用于存儲(chǔ)Int類型的屬性名numberOfEdits,它用于記錄屬性value被修改的次數(shù)。這個(gè)功能的實(shí)現(xiàn)通過(guò)屬性valuedidSet方法實(shí)現(xiàn),每當(dāng)給value賦新值時(shí)就會(huì)調(diào)用didSet方法,然后將numberOfEdits的值加一。

結(jié)構(gòu)體TrackedString和它的屬性value均沒(méi)有申明顯式訪問(wèn)級(jí)別,所以它們都擁有默認(rèn)的訪問(wèn)級(jí)別internal。但是該結(jié)構(gòu)體的numberOfEdits屬性使用private(set)修飾符進(jìn)行申明,這意味著numberOfEdits屬性只能在定義該結(jié)構(gòu)體的源文件中賦值。numberOfEdits屬性的Getter依然是默認(rèn)的訪問(wèn)級(jí)別internal,但是Setter的訪問(wèn)級(jí)別是private,這表示該屬性只有在當(dāng)前的源文件中是可讀寫的,而在當(dāng)前源文件所屬的模塊中它只是一個(gè)可讀的屬性。

如果你實(shí)例化TrackedString結(jié)構(gòu)體,并且多次對(duì)value屬性的值進(jìn)行修改,你就會(huì)看到numberOfEdits的值會(huì)隨著修改次數(shù)進(jìn)行變化:

var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
println("The number of edits is \(stringToEdit.numberOfEdits)")
// prints "The number of edits is 3"

雖然你可以在其他的源文件中實(shí)例化該結(jié)構(gòu)體并且獲取到numberOfEdits屬性的值,但是你不能對(duì)其進(jìn)行賦值。這樣就能很好的告訴使用者,你只管使用,而不需要知道其實(shí)現(xiàn)細(xì)節(jié)。

如果有必要你可以為GetterSetter方法設(shè)定顯式訪問(wèn)級(jí)別。下面的例子就是明確申明了public訪問(wèn)級(jí)別的TrackedString結(jié)構(gòu)體。結(jié)構(gòu)體的成員(包括numberOfEdits屬性)擁有默認(rèn)的訪問(wèn)級(jí)別internal。你可以結(jié)合publicprivate(set)修飾符把結(jié)構(gòu)體中的numberOfEdits屬性Getter方法的訪問(wèn)級(jí)別設(shè)置為public,而Setter方法的訪問(wèn)級(jí)別設(shè)置為private

public struct TrackedString {
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
        didSet {
            numberOfEdits++
        }
    }
    public init() {}
}

<a name="initializers"></a>

初始化

我們可以給自定義的初始化方法申明訪問(wèn)級(jí)別,但是要不高于它所屬類的訪問(wèn)級(jí)別。但必要構(gòu)造器例外,它的訪問(wèn)級(jí)別必須和所屬類的訪問(wèn)級(jí)別相同。

如同函數(shù)或方法參數(shù),初始化方法參數(shù)的訪問(wèn)級(jí)別也不能低于初始化方法的訪問(wèn)級(jí)別。

<a name="default_initializers"></a>

默認(rèn)初始化方法

Swift為結(jié)構(gòu)體、類都提供了一個(gè)默認(rèn)的無(wú)參初始化方法,用于給它們的所有屬性提供賦值操作,但不會(huì)給出具體值。默認(rèn)初始化方法可以參閱Default Initializers。默認(rèn)初始化方法的訪問(wèn)級(jí)別與所屬類型的訪問(wèn)級(jí)別相同。

注意:如果一個(gè)類型被申明為public級(jí)別,那么默認(rèn)的初始化方法的訪問(wèn)級(jí)別為internal。如果你想讓無(wú)參的初始化方法在其他模塊中可以被使用,那么你必須提供一個(gè)具有public訪問(wèn)級(jí)別的無(wú)參初始化方法。

<a name="default_memberwise_initializers_for_structure_types"></a>

結(jié)構(gòu)體的默認(rèn)成員初始化方法

如果結(jié)構(gòu)體中的任一存儲(chǔ)屬性的訪問(wèn)級(jí)別為private,那么它的默認(rèn)成員初始化方法訪問(wèn)級(jí)別就是private。盡管如此,結(jié)構(gòu)體的初始化方法的訪問(wèn)級(jí)別依然是internal。

如果你想在其他模塊中使用該結(jié)構(gòu)體的默認(rèn)成員初始化方法,那么你需要提供一個(gè)訪問(wèn)級(jí)別為public的默認(rèn)成員初始化方法。

<a name="protocols"></a>

協(xié)議

如果想為一個(gè)協(xié)議明確的申明訪問(wèn)級(jí)別,那么需要注意一點(diǎn),就是你要確保該協(xié)議只在你申明的訪問(wèn)級(jí)別作用域中使用。

協(xié)議中的每一個(gè)必須要實(shí)現(xiàn)的函數(shù)都具有和該協(xié)議相同的訪問(wèn)級(jí)別。這樣才能確保該協(xié)議的使用者可以實(shí)現(xiàn)它所提供的函數(shù)。

注意:如果你定義了一個(gè)public訪問(wèn)級(jí)別的協(xié)議,那么實(shí)現(xiàn)該協(xié)議提供的必要函數(shù)也會(huì)是public的訪問(wèn)級(jí)別。這一點(diǎn)不同于其他類型,比如,public訪問(wèn)級(jí)別的其他類型,他們成員的訪問(wèn)級(jí)別為internal。

<a name="protocol_inheritance"></a>

協(xié)議繼承

如果定義了一個(gè)新的協(xié)議,并且該協(xié)議繼承了一個(gè)已知的協(xié)議,那么新協(xié)議擁有的訪問(wèn)級(jí)別最高也只和被繼承協(xié)議的訪問(wèn)級(jí)別相同。比如說(shuō),你不能定義一個(gè)public的協(xié)議而去繼承一個(gè)internal的協(xié)議。

<a name="protocol_conformance"></a>

協(xié)議一致性

類可以采用比自身訪問(wèn)級(jí)別低的協(xié)議。比如說(shuō),你可以定義一個(gè)public級(jí)別的類,可以讓它在其他模塊中使用,同時(shí)它也可以采用一個(gè)internal級(jí)別的協(xié)議,并且只能在定義了該協(xié)議的模塊中使用。

采用了協(xié)議的類的訪問(wèn)級(jí)別取它本身和所采用協(xié)議中最低的訪問(wèn)級(jí)別。也就是說(shuō)如果一個(gè)類是public級(jí)別,采用的協(xié)議是internal級(jí)別,那么采用了這個(gè)協(xié)議后,該類的訪問(wèn)級(jí)別也是internal。

如果你采用了協(xié)議,那么實(shí)現(xiàn)了協(xié)議所必須的方法后,該方法的訪問(wèn)級(jí)別遵循協(xié)議的訪問(wèn)級(jí)別。比如說(shuō),一個(gè)public級(jí)別的類,采用了internal級(jí)別的協(xié)議,那么該類實(shí)現(xiàn)協(xié)議的方法至少也得是internal。

注意:Swift和Objective-C一樣,協(xié)議的一致性保證了一個(gè)類不可能在同一個(gè)程序中用不同的方法采用同一個(gè)協(xié)議。

<a name="extensions"></a>

擴(kuò)展

你可以在條件允許的情況下對(duì)類、結(jié)構(gòu)體、枚舉進(jìn)行擴(kuò)展。擴(kuò)展成員應(yīng)該具有和原始類成員一致的訪問(wèn)級(jí)別。比如你擴(kuò)展了一個(gè)公共類型,那么你新加的成員應(yīng)該具有和原始成員一樣的默認(rèn)的internal訪問(wèn)級(jí)別。

或者,你可以明確申明擴(kuò)展的訪問(wèn)級(jí)別(比如使用private extension)給該擴(kuò)展內(nèi)所有成員申明一個(gè)新的默認(rèn)訪問(wèn)級(jí)別。這個(gè)新的默認(rèn)訪問(wèn)級(jí)別仍然可以被單獨(dú)成員所申明的訪問(wèn)級(jí)別所覆蓋。

<a name="adding_protocol_conformance_with_an_extension"></a>

協(xié)議的擴(kuò)展

如果一個(gè)擴(kuò)展采用了某個(gè)協(xié)議,那么你就不能對(duì)該擴(kuò)展使用訪問(wèn)級(jí)別修飾符來(lái)申明了。該擴(kuò)展中實(shí)現(xiàn)協(xié)議的方法都會(huì)遵循該協(xié)議的訪問(wèn)級(jí)別。

<a name="generics"></a>

泛型

泛型類型或泛型函數(shù)的訪問(wèn)級(jí)別取泛型類型、函數(shù)本身、泛型類型參數(shù)三者中的最低訪問(wèn)級(jí)別。

<a name="type_aliases"></a>

類型別名

任何你定義的類型別名都會(huì)被當(dāng)作不同的類型,以便于進(jìn)行訪問(wèn)控制。一個(gè)類型別名的訪問(wèn)級(jí)別不可高于原類型的訪問(wèn)級(jí)別。比如說(shuō),一個(gè)private級(jí)別的類型別名可以設(shè)定給一個(gè)publicinternal、private的類型,但是一個(gè)public級(jí)別的類型別名只能設(shè)定給一個(gè)public級(jí)別的類型,不能設(shè)定給internalprivate 級(jí)別的類型。

注意:這條規(guī)則也適用于為滿足協(xié)議一致性而給相關(guān)類型命名別名的情況。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)