21协议Word文档格式.docx

上传人:b****7 文档编号:22244780 上传时间:2023-02-03 格式:DOCX 页数:25 大小:27.22KB
下载 相关 举报
21协议Word文档格式.docx_第1页
第1页 / 共25页
21协议Word文档格式.docx_第2页
第2页 / 共25页
21协议Word文档格式.docx_第3页
第3页 / 共25页
21协议Word文档格式.docx_第4页
第4页 / 共25页
21协议Word文档格式.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

21协议Word文档格式.docx

《21协议Word文档格式.docx》由会员分享,可在线阅读,更多相关《21协议Word文档格式.docx(25页珍藏版)》请在冰豆网上搜索。

21协议Word文档格式.docx

o2.13. 

继承

o2.14. 

构造过程

o2.15. 

析构过程

o2.16. 

自动引用计数

o2.17. 

可选链

o2.18. 

类型转换

o2.19. 

嵌套类型

o2.20. 

扩展

o2.21. 

协议

o2.22. 

泛型

o2.23. 

高级操作符

∙3. 

语言参考

o3.1. 

关于语言参考

o3.2. 

词法结构

o3.3. 

类型

o3.4. 

表达式

o3.5. 

语句

o3.6. 

声明

o3.7. 

特性

o3.8. 

模式

o3.9. 

泛型参数

o3.10. 

语法总结

∙GeneratedusingGitBook

翻译:

geek5nan

校对:

dabing1022

本页包含内容:

∙协议的语法(ProtocolSyntax)

∙对属性的规定(PropertyRequirements)

∙对方法的规定(MethodRequirements)

∙对突变方法的的规定(MutatingMethodRequirements)

∙协议类型(ProtocolsasTypes)

∙委托(代理)模式(Delegation)

∙在扩展中添加协议成员(AddingProtocolConformancewithanExtension)

∙通过扩展补充协议声明(DeclaringProtocolAdoptionwithanExtension)

∙集合中的协议类型(CollectionsofProtocolTypes)

∙协议的继承(ProtocolInheritance)

∙协议合成(ProtocolComposition)

∙检验协议的一致性(CheckingforProtocolConformance)

∙对可选协议的规定(OptionalProtocolRequirements)

协议(Protocol)用于定义完成某项任务或功能所必须的方法和属性,协议实际上并不提供这些功能或任务的具体实现(Implementation)--而只用来描述这些实现应该是什么样的。

类,结构体,枚举通过提供协议所要求的方法,属性的具体实现来采用(adopt)协议。

任意能够满足协议要求的类型被称为协议的遵循者。

协议可以要求其遵循者提供特定的实例属性,实例方法,类方法,操作符或下标脚本等。

协议的语法

协议的定义方式与类,结构体,枚举的定义都非常相似,如下所示:

protocolSomeProtocol{

//协议内容

}

在类型名称后加上协议名称,中间以冒号:

分隔即可实现协议;

实现多个协议时,各协议之间用逗号,分隔,如下所示:

structSomeStructure:

FirstProtocol,AnotherProtocol{

//结构体内容

如果一个类在含有父类的同时也采用了协议,应当把父类放在所有的协议之前,如下所示:

classSomeClass:

SomeSuperClass,FirstProtocol,AnotherProtocol{

//类的内容

对属性的规定

协议可以规定其遵循者提供特定名称与类型的实例属性(instanceproperty)或类属性(typeproperty),而不管其是存储型属性(storedproperty)还是计算型属性(calculateproperty)。

此外也可以指定属性是只读的还是可读写的。

如果协议要求属性是可读写的,那么这个属性不能是常量存储型属性或只读计算型属性;

如果协议要求属性是只读的(gettable),那么计算型属性或存储型属性都能满足协议对属性的规定,在你的代码中,即使为只读属性实现了写方法(settable)也依然有效。

协议中的属性经常被加以var前缀声明其为变量属性,在声明后加上{setget}来表示属性是可读写的,只读的属性则写作{get},如下所示:

varmustBeSettable:

Int{getset}

vardoesNotNeedToBeSettable:

Int{get}

如下所示,通常在协议的定义中使用class前缀表示该属性为类成员;

在枚举和结构体实现协议时中,需要使用static关键字作为前缀。

protocolAnotherProtocol{

classvarsomeTypeProperty:

如下所示,这是一个含有一个实例属性要求的协议:

protocolFullyNamed{

varfullName:

String{get}

FullyNamed协议定义了任何拥有fullName的类型。

它并不指定具体类型,而只是要求类型必须提供一个fullName。

任何FullyNamed类型都得有一个只读的fullName属性,类型为String。

如下所示,这是一个实现了FullyNamed协议的简单结构体:

structPerson:

FullyNamed{

String

letjohn=Person(fullName:

"

JohnAppleseed"

//john.fullName为"

这个例子中定义了一个叫做Person的结构体,用来表示具有指定名字的人。

从第一行代码中可以看出,它采用了FullyNamed协议。

Person结构体的每一个实例都有一个叫做fullName,String类型的存储型属性,这正好匹配了FullyNamed协议的要求,也就意味着,Person结构体完整的遵循了协议。

(如果协议要求未被完全满足,在编译时会报错)

这有一个更为复杂的类,它采用并实现了FullyNamed协议,如下所示:

classStarship:

FullyNamed{

varprefix:

String?

varname:

init(name:

String,prefix:

=nil){

self.name=name

self.prefix=prefix

}

String{

return(prefix?

prefix!

+"

:

)+name

varncc1701=Starship(name:

Enterprise"

prefix:

USS"

//ncc1701.fullName=="

USSEnterprise"

Starship类把fullName属性实现为只读的计算型属性。

每一个Starship类的实例都有一个名为name的必备属性和一个名为prefix的可选属性。

当prefix存在时,将prefix插入到name之前来为Starship构建fullName,prefix不存在时,则将直接用name构建fullName

对方法的规定

协议可以要求其遵循者实现某些指定的实例方法或类方法。

这些方法作为协议的一部分,像普通的方法一样清晰的放在协议的定义中,而不需要大括号和方法体。

注意:

协议中的方法支持变长参数(variadicparameter),不支持参数默认值(defaultvalue)。

如下所示,协议中类方法的定义与类属性的定义相似,在协议定义的方法前置class关键字来表示。

当在枚举或结构体实现类方法时,需要使用static关键字来代替。

classfuncsomeTypeMethod()

如下所示,定义了含有一个实例方法的的协议。

protocolRandomNumberGenerator{

funcrandom()->

Double

RandomNumberGenerator协议要求其遵循者必须拥有一个名为random,返回值类型为Double的实例方法。

(尽管这里并未指明,但是我们假设返回值在[0,1]区间内)。

RandomNumberGenerator协议并不在意每一个随机数是怎样生成的,它只强调这里有一个随机数生成器。

如下所示,下边的是一个遵循了RandomNumberGenerator协议的类。

该类实现了一个叫做线性同余生成器(linearcongruentialgenerator)的伪随机数算法。

classLinearCongruentialGenerator:

RandomNumberGenerator{

varlastRandom=42.0

letm=139968.0

leta=3877.0

letc=29573.0

Double{

lastRandom=((lastRandom*a+c)%m)

returnlastRandom/m

letgenerator=LinearCongruentialGenerator()

println("

Here'

sarandomnumber:

\(generator.random())"

//输出:

0.37464991998171"

Andanotherone:

0.729023776863283"

对突变方法的规定

有时不得不在方法中更改实例的所属类型。

在基于值类型(valuetypes)(结构体,枚举)的实例方法中,将mutating关键字作为函数的前缀,写在func之前,表示可以在该方法中修改实例及其属性的所属类型。

这一过程在ModifytingValueTypesfromWithinInstanceMethods章节中有详细描述。

如果协议中的实例方法打算改变其遵循者实例的类型,那么在协议定义时需要在方法前加mutating关键字,才能使结构体,枚举来采用并满足协议中对方法的规定。

注意:

用类实现协议中的mutating方法时,不用写mutating关键字;

用结构体,枚举实现协议中的mutating方法时,必须写mutating关键字。

如下所示,Togglable协议含有名为toggle的突变实例方法。

根据名称推测,toggle方法应该是用于切换或恢复其遵循者实例或其属性的类型。

protocolTogglable{

mutatingfunctoggle()

当使用枚举或结构体来实现Togglabl协议时,需要提供一个带有mutating前缀的toggle方法。

如下所示,OnOffSwitch枚举遵循了Togglable协议,On,Off两个成员用于表示当前状态。

枚举的toggle方法被标记为mutating,用以匹配Togglabel协议的规定。

enumOnOffSwitch:

Togglable{

caseOff,On

mutatingfunctoggle(){

switchself{

caseOff:

self=On

caseOn:

self=Off

varlightSwitch=OnOffSwitch.Off

lightSwitch.toggle()

//lightSwitch现在的值为.On

协议类型

尽管协议本身并不实现任何功能,但是协议可以被当做类型来使用。

使用场景:

∙协议类型作为函数、方法或构造器中的参数类型或返回值类型

∙协议类型作为常量、变量或属性的类型

∙协议类型作为数组、字典或其他容器中的元素类型

协议是一种类型,因此协议类型的名称应与其他类型(Int,Double,String)的写法相同,使用驼峰式写法

如下所示,这个示例中将协议当做类型来使用

classDice{

letsides:

Int

letgenerator:

RandomNumberGenerator

init(sides:

Int,generator:

RandomNumberGenerator){

self.sides=sides

self.generator=generator

funcroll()->

Int{

returnInt(generator.random()*Double(sides))+1

例子中又一个Dice类,用来代表桌游中的拥有N个面的骰子。

Dice的实例含有sides和generator两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器。

generator属性的类型为RandomNumberGenerator,因此任何遵循了RandomNumberGenerator协议的类型的实例都可以赋值给generator,除此之外,无其他要求。

Dice类中也有一个构造器(initializer),用来进行初始化操作。

构造器中含有一个名为generator,类型为RandomNumberGenerator的形参。

在调用构造方法时创建Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的实例给generator。

Dice类也提供了一个名为roll的实例方法用来模拟骰子的面值。

它先使用generator的random方法来创建一个[0-1]区间内的随机数种子,然后加工这个随机数种子生成骰子的面值。

generator被认为是遵循了RandomNumberGenerator的类型,因而保证了random方法可以被调用。

如下所示,这里展示了如何使用LinearCongruentialGenerator的实例作为随机数生成器创建一个六面骰子:

vard6=Dice(sides:

6,generator:

LinearCongruentialGenerator())

for_in1...5{

println("

Randomdicerollis\(d6.roll())"

//输出结果

//Randomdicerollis3

//Randomdicerollis5

//Randomdicerollis4

委托(代理)模式

委托是一种设计模式(译者注:

想起了那年UITableViewDelegate中的奔跑,那是我逝去的Objective-C。

),它允许类或结构体将一些需要它们负责的功能交由(委托)给其他的类型的实例。

委托模式的实现很简单:

定义协议来封装那些需要被委托的函数和方法,使其遵循者拥有这些被委托的函数和方法。

委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的所属类型(译者注:

只要求外部数据源遵循某协议)。

下文是两个基于骰子游戏的协议:

protocolDiceGame{

vardice:

Dice{get}

funcplay()

protocolDiceGameDelegate{

funcgameDidStart(game:

DiceGame)

funcgame(game:

DiceGame,didStartNewTurnWithDiceRolldiceRoll:

Int)

funcgameDidEnd(game:

DiceGame协议可以在任意含有骰子的游戏中实现,DiceGameDelegate协议可以用来追踪DiceGame的游戏过程

如下所示,SnakesAndLadders是SnakesandLadders(译者注:

ControlFlow章节有该游戏的详细介绍)游戏的新版本。

新版本使用Dice作为骰子,并且实现了DiceGame和DiceGameDelegate协议,后者用来记录游戏的过程:

classSnakesAndLadders:

DiceGame{

letfinalSquare=25

letdice=Dice(sides:

6,generator:

varsquare=0

varboard:

Int[]

init(){

board=Int[](count:

finalSquare+1,repeatedValue:

0)

board[03]=+08;

board[06]=+11;

board[09]=+09;

board[10]=+02

board[14]=-10;

board[19]=-11;

board[22]=-02;

board[24]=-08

vardelegate:

DiceGameDelegate?

funcplay(){

square=0

delegate?

.gameDidStart(self)

gameLoop:

whilesquare!

=finalSquare{

letdiceRoll=dice.roll()

.game(self,didStartNewTurnWithDiceRoll:

diceRoll)

switchsquare+diceRoll{

casefinalSquare:

breakgameLoop

caseletnewSquarewherenewSquare>

finalSquare:

continuegameLoop

default:

square+=diceRoll

square+=board[square]

.gameDidEnd(self)

这个版本的游戏封装到了SnakesAndLadders类中,该类采用了DiceGame协议,并且提供了dice属性和play实例方法用来遵循协议。

(dice属性在构造之后就不在改变,且协议只要求dice为只读的,因此将dice声明为常量属性。

在SnakesAndLadders类的构造器(initializer)初始化游戏。

所有的游戏逻辑被转移到了play方法中,play方法使用协议规定的dice属性提供骰子摇出的值。

delegate并不是游戏的必备条件,因此delegate被定义为遵循DiceGameDelegate协议的可选属性,delegate使用nil作为初始值。

DicegameDelegate协议提供了三个方法用来追踪游戏过程。

被放置于游戏的逻辑中,即play()方法内。

分别在游戏开始时,新一轮开始时,游戏结束时被调用。

因为delegate是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链来调用委托方法。

若delegate属性为nil,则delegate所调用的方法失效。

若delegate不为nil,则方法能够被调用

如下所示,DiceGameTracker遵循了DiceGameDelegate协议

classDiceGameTracker:

DiceGameDelegate{

varnumberOfTurns=0

DiceGame){

numberOfTurns=0

ifgameisSnakesAndLadders{

StartedanewgameofSnakesandLadders"

Thegameisusinga\(game.dice.sides)-sideddice"

Int){

++numberOfTurns

Rolleda\(diceRoll)"

Thegamelastedfor\(numberOfTurns)turns"

DiceGameTracker实现了DiceGameDelegate协议规定的三个方法,用来记录游戏已经进行的轮数。

当游戏开始时,numberOfTurns属性被赋值为0;

在每新一轮中递加;

游戏结束后,输出打印游戏的总轮数。

gameDidStart方法从game参数获取游戏信息并输出。

game在方法中被当做DiceGame类型而不是SnakeAndLadders类型,所以方法中只能访问DiceGame协议中的成员。

当然了,这些方法也可以在类型转换之后调用。

在上例代码中,通过is操作符检查game是否为 

SnakesAndLadders类型的实例,如果是,则打印出相应的内容。

无论当前进行的是何种游戏,game都遵循DiceGame协议以确保game含有dice属性,因此在gameDidStart方法中可以通过传入的game参数来访问dice属性,进而打印出dice的sides属性的值。

DiceGameTracker的运行情况,如下所示:

lettracker=DiceGameTracker()

letgame=SnakesAndLadders()

game.delegate=tracker

game.play()

//StartedanewgameofSnakesandLadders

//Thegameisusinga6-sideddice

//Rolleda3

//Rolleda5

//Rolleda4

//Thegamelastedfor4turns

在扩展中添加协议成员

即便无法修改源代码,依然可以通

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1