# Day12--我们用协定说好要这样做了,你一定得OK!

协定的语法其实算是大量的使用在结构与类别中,尤其需要更底层的作用的时候,协定算是提供了一个共识,让程序语言在撰写的时候,可以根据一些基本认知去创建东西,过去一直都认为协定是一个更底层的东西,但这样说其实很笼统,要说的话,它可以被认为是一种像共识一样的东西,所有的内容都会基於这样的共识去延伸进类别、结构、枚举中。
而这样的共识正反映在协定所建构的属性、方法中。故,本篇章将分为几个部分:

  1. 协定的意义
  2. 语法格式
  3. 对於属性、方法的规范
  4. 协定之下的建构器

协定的意义

协定(protocol)是 Swift 一个重要的特性,它会定义出为了完成某项任务或功能所需的方法、属性,协定本身不会实作这些任务跟功能,而仅仅只是表达出该任务或功能的名称。这些功能则都交由遵循协定的型别来实作,列举、结构及类别都可以遵循协定,遵循协定表示这个型别必须实作出协定定义的方法、属性或其他功能。(资料来源:Swift起步走)

有点像是协定定义出一个To Do List,而所有遵循协定的型别都必须照表操课,将需要的功能都实作出来。

Protocols are a way of describing what properties and methods something must have. You then tell Swift which types use that protocol — a process known as adopting or conforming to a protocol.

协定是一种方法去描述什麽样的属性、方法在其里面必须拥有,你接着告诉Swift什麽样的型别使用那样的协定,这被称为采用或遵守协议的过程。
综合上述,协定的功能就是提供一个原则,让它完成某个任务,而这些原则规范了某项任务所需要的方法、属性,但协定不会实作这些任务与功能。协定所提供的,就是一个原则,让结构(struct)、类别(class)、枚举(Enum)来遵守。受协定约束的这些型别,必须实作出受制於其定义的方法、属性等功能。

协定的语法格式

在第1–3行(或第5–7行)中,基本上提供的是协定的最基本样态

结构中的协定

如若是结构要使用协定,则以第9–11行为内容,提出结构名称後,便以冒号“:”(colon)隔开,再接着协定的名称,如若有复数个协定需要遵守,则以逗号“,”(comma)来作为协定间的区隔。

类别中的协定

其实类别的协定写作的方式几乎跟结构相似,但结构没有所谓的父子类别的功能,所以类别在表示时,先以「子类别:父类别」,这样的语法开头,随後,在父类别旁边以“,”继续将所需要的协定引入,如上述第17–19行所表示:
协定对於属性的规范
协定不能定义一个属性是储存属性或计算属性,而只是定义属性的名称及是实体属性或型别属性。此外还可以定义属性是唯读或是可读写的。

  1. 协定定义属性是可读写时,则遵循协定的型别定义的属性不能是常数属性或唯读的计算属性。
  2. 协定定义属性是唯读时,则遵循协定的型别定义的属性可以是唯读或依照需求改定义为可读写。(资料来源:Swift起步走)

继上述的说法,也就是协定是可以在其功能中,将协定所规范的属性定调为唯读或可读写这两种功能。

就上述之例子来说,可以读写的变数最後面的{ }里面会有get、set两者
而唯读的就只有get字样
实例来说:

变数Name就是一个唯读的例子,而具有协定的结构,则必须要因着协定的设定,而将其内部所设定的属性放进去结构里设定。

协定对於方法的规范

协定可以定义实体方法或型别方法以供遵循,而这些方法不需要大括号{}以及其内的内容(即不需要实作),而实作则是交给遵循协定的型别来做。
协定可以定义含有可变数量参数(variadic parameter)的方法。
协定不能为方法的参数提供预设值。

与属性的规则一样,协定中要定义型别方法时,必须在前面加上static关键字。而当一个类别遵循这个协定时,除了static还可以使用class关键字来定义类别的这个型别方法。(资料来源:Swift起步走)

协定定义方法的时候,是不需要{ }作为内容:

只需要:

把定义的方法写出来就可以了。
所以,在实际上的例子上,我们可以见到,我们在协定里面所写好的内容,就会在实际的类别使用上变成是类别必须要设定方法的内容,假若没有依照协定所给定的属性、方法下去写,则会报错。

上述对於协定中的方法有了基本的讨论後,接下来会提到的就是变异方法:

变异方法

使用mutating关键字放在func关键字前来定义变异方法(变异方法表示可以在方法中修改它所属的实体以及实体的属性的值)。

遵循一个包含变异方法的协定时,列举跟结构定义时必须加上mutating关键字,而类别定义时则不用加上。(资料来源:Swift起步走)

总之,在举出变异方法时,变异方法是可以修改实体以及属性的值的,不过,变异方法在结构、枚举上与类别上则有两者不同的区别:

在协定中有变异方法时:
结构、枚举定义必须加上mutating
类别定义则否

以下则一实例:

就以enum case作为是一个变异的方法来讨论,我们可以直接看到第5行的地方举了两个case:A、B,而SomeEnum中必须要有mutating func someMethod( )在里面,其中为一个假如遇到A,就变成B,遇到B,就变成A的案例。

所以,在实体transition里面,就是case.A,然後加入someMethod( )後,就会变成B

所以,变异方法在使用上,就是一个可以改变属性的方法,如果遇到需要变异的情况,可以大方的使用。

协定中的建构器

如果是一个类别遵循一个含有建构器的协定时,无论是指定建构器或便利建构器,都必须为类别的建构器加上required修饰符,以确保所有子类别也必须定义这个建构器,从而符合协定(如果类别已被加上final,则不需要为其内的建构器加上required,因为final类别不能再被子类别继承)(资料来源:Swift起步走)

也就是说,我们假若今天创建一个协定後,而这个协定里面具有建构器,无论是指定或便利建构器,我们都必须在类别里面的建构器加上required字样:

如果一个子类别覆写了父类别的指定建构器,且此建构器满足了某个协定的要求,则该建构器必须同时加上required和override,如下:

所以,如果是基於具有协定的情况下,我们若要在子类别中覆写父类别的内容,我们的建构器就必须要有三个字样:required、override、init( ),这三样齐全,才是覆写父类的子类建构器应有的样子。

综合本篇章所提及的内容,以下有三个重点会提及:

本篇章首先提到的是协定的运作方式,协定主要制定的是让结构、枚举、类别遵守的属性、方法的规范,假若在协定中有提到关於属性、方法在其中,使用该协定的结构、枚举、类别就应该在其内容中有该属性与该方法的存在。
协定可以是唯读(get),也可以是可读写(set)的两种状态,端看设计者如何应用。

协定中如果具有建构器,在子类别中需要注明required,而假若需要覆写父类建构器的内容,则以required override init()来处理。

tags: 铁人赛

<<:  Day25-Kaggle Titanic迈进前5% part(2)

>>:  Progressive Web App 存取本机档案: File System Access API (14)

Day22 : 【TypeScript 学起来】Generic Function 泛型函式

上一篇介绍了 Generic 泛型, 其实这篇差不多意思 XDD 主要针对 Generic Fun...

密码是支持单因素身份验证的最佳机制

-数字身份模型(来源:NIST SP 800 63-3) “秘密”是用於验证主体身份的最关键元素。...

Day 30. 要别人看不懂,还是让自己看不懂的 - 混淆 Obfuscation

App 混淆再资安保护领域来说,可谓是最复杂的一环,也是最重要的一环 但是资安检测无法有个标准的检...

VMware虚拟机安装苹果 MacOS系统

首先下载并安装最新的VMware Workstation虚拟机,此次演示安装虚拟机版本VMware ...

[Angular] Day9. Transforming Data Using Pipes

在上一章中介绍了如何在 template 中插入 component 的变量,而本章节要介绍如何使用...