Swift語法2.22(協議)

本文參考了Swift2.2與3.0的語法,在少數地方添加了自我理解與示例.

協議(Protocols)

protocol 規定了 用來實現某一特定工作或者功能 所必需的 方法屬性

類,結構體枚舉類型都可以遵循協議,并必須提供具體實現來完成協議規定的方法功能

任意能夠滿足協議要求的類型被稱為這個協議的遵循者

可以對協議進行擴展

協議的語法

協議的定義方式與類,結構體,枚舉的定義非常相似。
<pre>
<code>
protocol SomeProtocol { // 協議內容 }
</code>
</pre>

使類遵循某個協議,需要在類型名稱后加上協議名稱,中間以 : 分隔,作為類型定義的一部分。
遵循多個協議時,各協議之間用 , 分隔
<pre>
<code>
struct SomeStructure: FirstProtocol, AnotherProtocol { // 結構體內容 }
</code>
</pre>

如果類在遵循協議的同時擁有父類,應該將父類名放在協議名之前,以逗號分隔
<pre>
<code>
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { // 類的內容 }
</code>
</pre>

對屬性的規定

協議 可以 規定其遵循者 提供 實例屬性(instance property)類屬性(type property)

不用指定存儲型屬性(stored property)還是計算型屬性(calculate property)

此外還必須指明 屬性是 只讀屬性 還是 讀寫屬性

若協議規定屬性是讀寫屬性,那這個屬性不能是常量或只讀的計算屬性。
若協議規定屬性是只讀屬性,如果你代碼需要的話,該屬性也可以是可寫的

<pre>
<code>
protocol SomeProtocol { var mustBeSettable : Int { get set } //讀寫屬性 var doesNotNeedToBeSettable: Int { get }//只讀屬性 }
</code>
</pre>

在協議中定義類屬性(type property)時,總是使用static關鍵字作為前綴。
協議的遵循者是類時,定義該類時可以使用classstatic關鍵字來聲明類屬性:
<pre>
<code>
protocol AnotherProtocol { static var someTypeProperty: Int { get set } }
</code>
</pre>

如下所示,這是一個含有一個實例屬性要求的協議:
<pre>
<code>
protocol FullyNamed { var fullName: String { get }//只讀屬性(代碼需要時也可以是可寫的) }
</code>
</pre>

這個協議表示,任何遵循FullyNamed協議的類型,都必須提供一個只讀的String類型實例屬性 。

下面是一個遵循FullyNamed協議的簡單結構體:
<pre>
<code>
struct Person: FullyNamed//遵循FullyNamed協議 { var fullName: String } var john = Person(fullName: "John Appleseed") print(john.fullName)//可讀 john.fullName = "JOHN"http://可寫 print(john.fullName) //John Appleseed //JOHN
</code>
</pre>

這個例子中定義了一個叫做Person的結構體,用來表示具有名字的人。從第一行代碼中可以看出,它遵循了協議。
Person結構體的每一個實例都有一個String類型的存儲屬性fullName,滿足了FullyNamed協議的要求,也就是意味著,Person結構體完整的遵循了協議.

對方法的規定

協議可以要求其遵循者實現某些指定實例方法類型方法

這些方法作為協議的一部分放在協議的定義中,但是不需要大括號和方法體。(只聲明,不需要實現)

協議中定義的方法支持可變參數 , 不支持默認參數

在協議中定義類方法的時候,總是使用static關鍵字作為前綴。

當協議的遵循者是類的時候,你可以在類的實現中使用static或者class來實現協議中的類型方法:
<pre>
<code>
protocol SomeProtocol { static func someTypeMethod() }
</code>
</pre>

下面的例子定義了含有一個實例方法的協議:
<pre>
<code>
protocol RandomNumberGenerator { func random() -> Double }
</code>
</pre>

RandomNumberGenerator協議要求其遵循者必須擁有一個名為random, 返回值類型為Double的實例方法。
如下所示,下邊的是一個遵循了RandomNumberGenerator協議的類。
<pre>
<code>
class LinearCongruentialGenerator:RandomNumberGenerator { func random() -> Double { return 1.01 } }
</code>
</pre>

對Mutating實例方法的規定

可以在協議中定義Mutating實例方法(在方法前加mutating關鍵字),使協議的遵循者的實例調用該方法時能夠修改實例和實例的屬性

注意
實現協議中的mutating方法時,不用寫mutating關鍵字
結構體,枚舉實現協議中的mutating方法時,必須寫mutating關鍵字。

如下所示, Togglable 協議含有名為 toggle 的實例方法。
根據名稱推測, toggle() 方法將通過改變實例屬性,來切換遵循該協議的實例的狀態。
toggle() 方法在定義的時候,使用mutating關鍵字標記,這表明當它被調用時該方法將會改變協議遵循者實例
<pre>
<code>
protocol Togglable { mutating func toggle() }
</code>
</pre>

使用枚舉結構體來實現Togglable協議時,需要提供一個帶有mutating前綴的toggle方法。
eg.
<pre>
<code>
enum OnOffSwitch: Togglable { case Off, On mutating func toggle() { switch self { case Off: self = On case On: self = Off } } } var lightSwitch = OnOffSwitch.Off print(lightSwitch.hashValue) lightSwitch.toggle() print(lightSwitch.hashValue) //0 //1
</code>
</pre>
使用class來實現Togglable協議時,提供的toggle方法不需要有前綴mutating
<pre>
<code>
class OnOffSwitch: Togglable { var onOrOff : Bool = false func toggle() { if self.onOrOff == false { self.onOrOff = true } else { self.onOrOff = false } } } let lightSwitch = OnOffSwitch() print(lightSwitch.onOrOff) lightSwitch.toggle() print(lightSwitch.onOrOff) //false //true
</code>
</pre>

對構造器的規定

協議可以要求它的遵循者實現指定的構造器
在協議的定義里寫下構造器的聲明,但不需要寫花括號和構造器的實體:
<pre>
<code>
protocol SomeProtocol { init(someParameter: Int) }
</code>
</pre>

協議中規定的構造器在類中的實現

你可以在遵循該協議的類中實現構造器,并指定其為類的指定構造器(designated initializer)或者便利構造器(convenience initializer)。
在這兩種情況下,在類的定義中 實現構造器時 必須 標上 required修飾符
(因為遵循協議,所以必須實現協議中的構造器)
eg.
<pre>
<code>
class SomeClass: SomeProtocol { required init(someParameter: Int) { //構造器實現 } }
</code>
</pre>

使用required修飾符可以保證:所有的遵循該協議的子類,能為構造器規定提供一個顯式的實現
關于required構造器的更多內容,請參考必要構造器

注意
如果類已經被標記為final,那么在協議構造器的實現中不需要使用required修飾符
因為final類不能有子類
關于final修飾符的更多內容,請參見防止重寫

如果一個子類遵循協議并需要實現協議中規定的構造器同時子類重寫了父類的指定構造器,那么該構造器的實現需要被同時標示requiredoverride修飾符:

<pre>
<code>
`
protocol SomeProtocol
{
init()
}

class SomeSuperClass
{
init()
{
// 構造器的實現
}
}

class SomeSubClass: SomeSuperClass, SomeProtocol
{
//因為遵循協議,需要加上"required";
//因為繼承自父類,需要加上"override"
required override init()
{
// 構造器實現
}
}
`
</code>
</pre>

可失敗構造器的規定

可以通過給協議中添加可失敗構造器來使遵循該協議的類型必須實現該可失敗構造器

如果在協議中定義一個可失敗構造器,則在遵循該協議的類型中必須添加同名同參數的可失敗構造器非可失敗構造器

如果在協議中定義一個非可失敗構造器,則在遵循該協議的類型中必須添加同名同參數的非可失敗構造器隱式解析類型的可失敗構造器( init! )

協議可以被當做類型來使用

盡管協議本身并不實現任何功能(只聲明屬性和方法)
但是協議可以被當做類型來使用

協議可以像其他普通類型一樣使用,使用場景:

作為函數、方法或構造器中的參數類型或返回值類型
作為常量、變量或屬性的類型
作為數組、字典或其他容器中的元素類型

注意

協議是一種類型,因此協議類型的名稱應與其他類型(Int,Double,String)的寫法相同,使用大寫字母開頭駝峰式寫法,例如(FullyNamed)

如下所示,這個示例中將協議當做類型來使用:
<pre>
<code>
`
protocol SomeProtocol//協議SomeProtocol可以作為類型來使用
{
func protocolFunc() -> Double
}

//類Zunxunzhe遵循SomeProtocol協議
//或者 理解為 類Zunxunzhe是SomeProtocol協議類型的子類
class Zunxunzhe: SomeProtocol
{
func protocolFunc() -> Double
{
return 3.14
}
}

class SomeClass
{
//屬性aProtocol的類型為SomeProtocol協議類型
//因此任何遵循了SomeProtocol協議的類型的實例都可以賦值給屬性aProtocol
let aProtocol: SomeProtocol

//SomeClass類中的構造器的 參數aProtocol類型 是 SomeProtocol協議類型
//在調用構造方法時創建SomeClass的實例時,可以將任何遵循 SomeProtocol協議的實例作為參數。
init(aProtocol: SomeProtocol)
{
self.aProtocol = aProtocol
}

func toInt() -> Int
{
    return Int(aProtocol.protocolFunc())
}

}

//前面代碼中規定了 :
//類Zunxunzhe遵循SomeProtocol協議
//或者 理解為 類Zunxunzhe是SomeProtocol協議類型的子類
let instance = SomeClass(aProtocol: Zunxunzhe())
print(instance.toInt())
//3
`
</code>
</pre>

委托模式

委托是一種設計模式,
委托模式允許結構體將一些需要它們負責的功能 委托給 其他的類型的實例

委托模式的實現很簡單:
定義協議封裝那些需要被委托的函數和方法
使其遵循者 擁有 這些被委托的函數和方法
從而將函數和方法實現的功能 委托給 遵循者的實例

在擴展中使已存在的類型遵循協議

即便無法修改源代碼,依然可以通過擴展(Extension)擴充已存在類型(譯者注: 類,結構體,枚舉等)
擴展可以為已存在的類型添加屬性,方法,下標腳本,協議等成員。

詳情請在擴展章節中查看。

注意
通過擴展使已存在的類型遵循協議時,該類型的所有實例也會獲得協議中的方法

在擴展的時候,協議名稱寫在類型名之后,以冒號隔開,在大括號內寫明新添加的協議內容
eg.
<pre>
<code>
`
protocol TextRepeatable
{
func repeatText()->String
}
extension NSString : TextRepeatable
{
func repeatText()->String
{
return (self as String) + (self as String)
}
}

`
</code>
</pre>

通過擴展,為NSString類添加新的 成員TextRepresentable協議使得NSString類遵循了一個新的協議TextRepeatable

現在所有NSString的實例都遵循了TextRepresentable協議:
<pre>
<code>
let nsstr = NSString.init(string: "abc") print(nsstr.repeatText()) //abcabc
</code>
</pre>

同樣NSInteger類也可以通過擴展的方式來遵循TextRepresentable協議
eg.
<pre>
<code>
extension NSInteger : TextRepeatable { func repeatText()->String { return String(self) + String(self) } } let int101 = NSInteger.init(101) print(int101.repeatText()) //101101
</code>
</pre>

通過擴展來補充聲明類型遵循協議

當一個類型已經實現了協議中的所有要求,卻沒有聲明遵循該協議
可以通過空的擴展補充聲明遵循協議
eg.
<pre>
<code>
struct SomeStruct { var str :String func repeatText()->String { return self.str + self.str } }
</code>
</pre>

雖然結構體SomeStruct實現了協議TextRepeatable規定的方法repeatText,但是沒有聲明遵循該協議
所以結構體SomeStruct的類型不會自動轉變為協議類型TextRepeatable

可以通過空的擴展使結構體SomeStruct補充遵循協議TextRepeatable
<pre>
<code>
extension SomeStruct : TextRepeatable {}
</code>
</pre>

此時SomeStruct的實例可以作為TextRepresentable類型使用
eg.
<pre>
<code>
let someStruct = SomeStruct.init(str: "asdf") let someTextRepeatable : TextRepeatable = someStruct print(someTextRepeatable.repeatText()) //asdfasdf
</code>
</pre>

協議類型的集合

協議類型可以在集合中使用
下面的例子創建了一個類型為[TextRepresentable]的數組:
<pre>
<code>
`
let nsstr = NSString.init(string: "abc")//nsstr:NSString
let int101 = NSInteger.init(101)//int101:NSInteger
let someStruct = SomeStruct.init(str: "asdf")//someStruct:SomeStruct

let things: [TextRepeatable] = [nsstr,int101,someStruct]

for thing in things//thing:TextRepeatable
{
print(thing.repeatText())
}
//abcabc
//101101
//asdfasdf
`
</code>
</pre>

thing被當做是TextRepeatable類型而不是NSString,NSInteger, SomeStruct等類型,即使真實的實例是它們中的一種類型。
盡管如此,由于它是TextRepeatable類型,任何TextRepeatable都擁有實例方法repeatText,所以循環訪問 thing.repeatText() 是安全的。

協議的繼承

協議能夠繼承一個或多個其他協議,可以在繼承的協議基礎上增加新的協議要求
協議的繼承語法與類的繼承相似,多個被繼承的協議間用逗號分隔:
<pre>
<code>
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // 協議定義 }
</code>
</pre>

下例中定義了2個協議protocol1,protocol2
protocol2繼承自protocol1。
任何遵循protocol2協議的類型在滿足該協議的要求時,也必須滿足protocol1協議的要求
eg.
<pre>
<code>
protocol protocol1 { func func1() } protocol protocol2:protocol1 { func func2() } extension String:protocol2 { func func1() { print("func1 : + \(self)") } func func2() { print("func2 : + \(self)") } } let hehe = "hehe" hehe.func1() hehe.func2() //func1 : + hehe //func2 : + hehe
</code>
</pre>

類專屬協議

你可以在協議的繼承列表中,通過添加class關鍵字,限制協議只能被class類型適配并遵循
結構體或枚舉不能遵循該協議
class關鍵字必須是第一個出現在協議的繼承列表中,其后,才是其他繼承協議。
<pre>
<code>
`
protocol aProtocol
{
func hehe()
}

//SomeClassOnlyProtocol協議只能被類(class)類型適配并遵守
//SomeClassOnlyProtocol協議繼承aProtocol協議
protocol SomeClassOnlyProtocol: class,aProtocol
{
func pFunc()
}
//通過擴展使NSString類遵循協議SomeClassOnlyProtocol
extension NSString:SomeClassOnlyProtocol
{
func hehe() {
print("hehe + (self)")
}
func pFunc()
{
print("pFunc + (self)")
}
}
let str : NSString = "haha"
str.hehe()
str.pFunc()
//hehe + haha
//pFunc + haha
`
</code>
</pre>

在以上例子中,協議SomeClassOnlyProtocol只能類(class)類型適配。
如果嘗試讓結構體或枚舉類型適配該協議,則會出現編譯錯誤。
eg.
<pre>
<code>
extension String:SomeClassOnlyProtocol //?此處報錯:Non-class type 'String' cannot conform to class protocol 'SomeClassOnlyProtocol' //因為String類型是是通過結構體實現的 { func hehe() { print("hehe + \(self)") } func pFunc() { print("pFunc + \(self)") } }
</code>
</pre>

注意
當協議要求(或假設)它的遵循者類型必須是引用類型而非值類型時,應該采用類專屬協議
關于引用類型,值類型的更多內容,請查看結構體和枚舉是值類型類是引用類型

協議合成

有時候需要同時遵循多個協議
你可以將多個協議采用protocol<SomeProtocol, AnotherProtocol>這樣的格式進行組合,稱為協議合成
你可以在<>中羅列多個你想要遵循的協議,以逗號分隔

下面的例子中,將 Named 和 Aged 兩個協議按照上述的語法組合成一個協議:
<pre>
<code>
protocol Named { var name: String { get } } protocol Aged { var age: Int { get } } struct Person: Named, Aged { var name: String var age: Int } func wishHappyBirthday(celebrator: protocol<Named, Aged>) { print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") } let birthdayPerson = Person(name: "Malcolm", age: 21) wishHappyBirthday(birthdayPerson) //Happy birthday Malcolm - you're 21!
</code>
</pre>

Person結構體遵循了Named協議和Aged協議

wishHappyBirthday函數的參數類型為protocol<Named,Aged>
因此任意遵循這兩個協議的類型的實例都可以作為參數傳入wishHappyBirthday(_:)函數。

注意
協議合成不會生成一個新協議,而是將多個協議合成為一個臨時的協議

檢驗是否符合協議

使用is檢查實例是否遵循某一協議
使用as強制轉換實例為某一協議類型

檢查和轉化的語法詳情查看類型轉換
is用來檢查實例是否遵循了某個協議
as?返回一個可選值,當實例遵循協議時,返回該協議類型;否則返回nil。
as!用以強制向下轉換,如果強轉失敗,會引起運行時錯誤。

下面的例子定義了一個HasArea的協議,要求有一個Double類型的只讀屬性area
<pre>
<code>
protocol HasArea { var area: Double { get } }
</code>
</pre>

如下所示,定義了 Circle 和 Country 類,它們都遵循HasArea協議:
<pre>
<code>
`
class Circle: HasArea
{
let pi = 3.1415927
var radius: Double
var area: Double
{
return pi * radius * radius
}
init(radius: Double)
{
self.radius = radius
}
}

class Country: HasArea
{
var area: Double
init(area: Double)
{
self.area = area
}
}
`
</code>
</pre>

Circle類把計算屬性area實現為基于存儲屬性radius, Country類則把area實現為存儲屬性。
這兩個類都遵循了HasArea協議。

如下所示, Animal是一個沒有實現HasArea協議的類:
<pre>
<code>
class Animal { var legs: Int init(legs: Int){ self.legs = legs } }
</code>
</pre>

Circle,Country,Animal并沒有一個相同的基類,然而,它們都是類,它們的實例都可以作為AnyObject類型的變量,存儲在同一個數組中
<pre>
<code>
let objects: [AnyObject] = [ Circle(radius: 2.0), Country(area: 243_610), Animal(legs: 4) ]
</code>
</pre>

如下所示, objects數組可以被迭代,對每一個元素進行檢查,看它是否遵循了HasArea協議
eg.
<pre>
<code>
for object in objects { if let objectWithArea = object as? HasArea { print("Area is \(objectWithArea.area)") } else { print("Something that doesn't have an area") } } // Area is 12.5663708 // Area is 243610.0 // Something that doesn't have an area
</code>
</pre>

當元素遵循HasArea協議時,通過as?操作符可以將其可選綁定到objectWithArea常量上.
objects數組中元素的類型并不會因為類型轉換而丟失類型信息,它們仍然是Circle,Country,Animal類型.

對協議中可選成員的規定

協議可以含有可選成員,其遵守者可以選擇是否實現這些成員

在協議中使用optional關鍵字作為前綴定義可選成員

當需要使用可選規定的方法或者屬性時,他的類型自動會變成可選的
比如,一個定義為(Int)->String類型的方法變成( (Int)->String )?
需要注意的是整個方法定義包裹在可選中(整個方法是可選的)

協議規定的可選成員在調用時使用可控鏈 ,因為協議的遵循者可能沒有實現可選內容。
像someOptionalMethod?(someArgument)這樣,你可以在可選方法名稱后加上?檢查該方法是否被實現

詳細內容在可空鏈式調用章節中查看。

注意

可選協議只能在含有@objc前綴的協議中生效。
這個前綴表示協議將暴露給Objective-C代碼。

即使你不打算和Objective-C有什么交互,如果你想要指明協議包含可選屬性,那么還是要加上@objc前綴。

@objc的協議 只能繼承自Objective-C類的類或者其他@objc類來遵循。

@objc的協議不能結構體枚舉遵循。

下面的例子定義了一個叫Counter的整數加法類
<pre>
<code>
@objc class Counter { var count = 0 var dataSource: CounterDataSource? func increment() { if let amount = dataSource?.incrementForCount?(count) { count += amount } else if let amount = dataSource?.fixedIncrement? { count += amount } } }
</code>
</pre>

CounterDataSource協議中聲明了兩個可選成員
<pre>
<code>
@objc protocol CounterDataSource { optional func incrementForCount(count: Int) -> Int //可選方法 optional var fixedIncrement: Int { get }//可選屬性 }
</code>
</pre>

ThreeSource類實現了CounterDataSource協議
雖然ThreeSource類只實現了可選屬性fixedIncrement

<pre>
<code>
`
@objc class ThreeSource: CounterDataSource
{
let fixedIncrement = 3
}

var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4
{
counter.increment()
print(counter.count)
}
// 3
// 6
// 9
// 12
`
</code>
</pre>

對協議進行擴展

對協議進行擴展 可以 為遵循者 提供方法或屬性的默認的實現

所有協議的遵循者,在不用任何修改的情況下,都自動得到了這個擴展所增加的屬性或方法的默認實現

例如,可以擴展RandomNumberGenerator協議,為其遵循者提供默認的randomBool方法。

<pre>
<code>
`
//協議RandomNumberGenerator
protocol RandomNumberGenerator
{
//協議RandomNumberGenerator聲明的方法random
//需要遵循者提供方法random實現
func random()->Double
}

//擴展協議RandomNumberGenerator
extension RandomNumberGenerator
{
//為遵循者提供方法randomBool默認的實現,遵循者可以自動獲得
func randomBool() -> Bool
{
return random() > 0.5
}
}

//Num類 遵循 協議RandomNumberGenerator
class Num: RandomNumberGenerator
{
//Num類 需要提供 RandomNumberGenerator協議的定義中規定的方法random實現
func random()->Double
{
return 3.14
}
//而Num類會自動獲得RandomNumberGenerator協議的擴展中的方法randomBool的默認實現,因此不用實現
}

let num = Num()
print(num.random())
print(num.randomBool())
//3.14
//true
`
</code>
</pre>

如果協議的遵循者擴展協議中的屬性/方法 提供了自己的實現,那么遵循者提供的實現將被使用
eg.
<pre>
<code>
//Num類 遵循 協議RandomNumberGenerator class Num: RandomNumberGenerator { func random()->Double { return 3.14 } //Num類 對協議的擴展中的方法randomBool提供了自己的實現 func randomBool() -> Bool { print("always false") return false } } let num = Num() print(num.random()) print(num.randomBool()) //3.14 //always false //false
</code>
</pre>

為擴展協議添加限制條件

擴展協議的時候,可以指定一些限制,只有滿足這些限制的協議的遵循者,才能獲得協議擴展所提供的屬性和方法

這些限制寫在被擴展協議名之后,使用where關鍵字來描述限制情況
eg:
<pre><code>`
protocol TextRepresentInBig
//TextRepresentInBig協議用來作為對CollectionType協議的擴展的限制條件
{
var descriptionInBig: String { get }
}

extension CollectionType where Generator.Element : TextRepresentInBig
//通過擴展為CollectionType協議添加限制條件:只適用于集合類型中元素遵循TextRepresentInBig的情況
//只有滿足限制條件的CollectionType協議的遵循者才能獲得此擴展中的計算屬性CollectionDescription
{
var CollectionDescription: String {
let itemsAsText = self.map { $0.descriptionInBig }
return itemsAsText.joinWithSeparator("/")
}
}
struct Text:TextRepresentInBig
//Text類型遵循協議TextRepresentInBig
{
var text: String
var descriptionInBig: String
{
return text.uppercaseString
}
}
let text1 = Text(text: "haha")
let text2 = Text(text: "HEHE")
let text3 = Text(text: "HOho")
let textArray = Array.init(arrayLiteral: text1,text2,text3)
//Array類型默認遵循協議CollectionType
//因為Array類型的實例textArray中的元素類型為Text,Text類型遵循協議TextRepresentable
//所以textArray滿足限制條件:where Generator.Element,獲得擴展中的計算屬性CollectionDescription
print(textArray.CollectionDescription)
//HAHA/HEHE/HOHO
`</code></pre>

注:
如果協議有多個擴展并在多個擴展中提供了相同的方法/屬性的不同的實現,而該協議的遵循者同時滿足了多個擴展的限制條件,那么遵循者將會使用限制條件嚴格的那個擴展中的實現。

eg:
<pre>
<code>
`
protocol TextRepresentInBig
{
var descriptionInBig: String { get }
}
protocol TextRepresentInDoubled
{
var descriptionInDoubled: String { get }
}

extension CollectionType where Generator.Element : TextRepresentInBig
{
var CollectionDescription: String {
let itemsAsText = self.map { $0.descriptionInBig }
return itemsAsText.joinWithSeparator("/")
}
}
extension CollectionType where Generator.Element : TextRepresentInDoubled , Generator.Element : TextRepresentInBig
{
var CollectionDescription: String
{
let itemsAsText = self.map { $0.descriptionInDoubled }
return itemsAsText.joinWithSeparator("\")
}
}
struct Text:TextRepresentInBig,TextRepresentInDoubled
{
var text: String
var descriptionInBig: String
{
return text.uppercaseString
}
var descriptionInDoubled: String
{
return text + text
}
}
let text1 = Text(text: "haha")
let text2 = Text(text: "HEHE")
let text3 = Text(text: "HOho")
let textArray = Array.init(arrayLiteral: text1,text2,text3)
print(textArray.CollectionDescription)
//hahahaha\HEHEHEHE\HOhoHOho
`
</code>
</pre>


OVER

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容