十一.使用协议作为类型
1.协议也相当于一种类型,与枚举、结构体、类相比,协议相当于一种抽象的类型,它被彻底抽象成只定义规范,不负责实现。因此定义协议之后,就可以像枚举、结构体、类那样当作类型来使用,只是协议不能直接用于创建实例,协议可以做如下方面的用途:
(1)可使用协议声明变量
(2)可使用协议作为函数、方法、构造器的形参类型、返回值类型
(3)可使用协议作为is、as等运算符的***后***一个操作数
2.举个栗子:
protocol Eatable
{
//定义实例方法
Func taste()
//协议使用class修饰类型方法
class func test(msgs : String…)
}
//实现Eatable协议
struct Pie : Eatable
{
var weight : Double
//定义实例方法
func taste()
{
print(“饼干很好吃。。。”)
}
//结构体使用static修饰类型方法
static func test (msgs : String…)
{
print(“test method”)
for msg in msgs
{
print(“msg is: ”\(msg))
}
}
}
class Apple : Eatable
{
var name : String
init(name : String)
{
self.name = name
}
//定义实例方法
func taste()
{
print("苹果很好吃")
}
//类使用class修饰类型方法
class func test (msgs : String...)
{
print("apple test")
}
}
//使用Eatable声明变量,将Apple实例赋值给food,这是向上转型
var food1 : Eatable = Apple(name : "红富士")
//使用Eatable声明变量,将Pie实例赋值给food,这是向上转型
var food2 : Eatable = Pie(weight : 1.2)
//分别调用food1,food2里面的方法,这是多态
food1.taste()
food2.taste()
//定义一个函数,该函数的形参是个数可变的Eatable类型的形参
func eat(foods : Eatable...)
{
for food in foods
{
food.taste()
}
}
//由于该函数的参数要求是Eatable类型,所以既可以传入Apple,也可以传入Pie
eat(Apple(name : "apple"), Pie(weight : 2.2))
//声明并反问Eatable类型的数组
var foodArray : [Eatable] = [Apple(name : "apple1"), Pie(weight : 1.2),Apple(name : "apple2"), Pie(weight : 2.2),Apple(name : "apple3"), Pie(weight : 3.2),Apple(name : "apple4"), Pie(weight : 4.2)]
for food in foodArray
{
if let ap = food as? Apple
{
print("这个Eatable是苹果,名字为:\(ap.name)")
}
else let pie = food as? Pie
{
print("这个Eatable是饼干,重量为: \(pie.weight)")
}
}
3.通过上面可以看出,实现某个协议时,也集成某个类的本质是一样的,协议的实现类型,也相当于协议的特殊子类,因此协议实现类型的实例,完全可以当成协议实例使用。
4.一般来说,程序通常应该面向协议编程,就像其他语言倡导的面向接口编程一样,面向协议编程能提供更好的灵活性,这也是多态的价值所在。
十二.合成协议
1. Swift还允许将多个协议合成一个临时的类型,这种用法被为合成协议。合成协议的语法格式为:
protocol<协议1,协议2,协议3,....>
2.对于采用这种合成协议声明的变量、定义的参数、声明的返回值,必须同时实现合成协议里面的所有协议。
十三.通过扩展为已有的类型添加协议
1.前面已经知道通过扩展可以为已有的类型添加计算属性、方法、下标、构造器等。不仅如此,使用扩展还可以为已有的类型添加协议。
2.举个栗子:下面的代码通过扩展让String实现Eatable协议。
extension String : Eatable
{
//实现Eatable协议中的方法
func taste()
{
print("\(self) taste")
}
class func test()
{// ....}
}
3.在某些极端情况下,如果已有类型已经实现了协议中的要求,则可以更简单地通过扩展让该类型实现这个协议————此时扩展的花括号内不需要任何代码
4.举个栗子:
protocol Emptyable
{
var isEmpty : Bool {get}
}
extension String : Emptyable{}
//定义一个方法,该方法需要Emptyable参数
func foo(arg: Empayable)
{
print("arg is empty or not : (\arg.isEmpty)")
}
//调用foo方法,传入String即可,(因为String实现了Emptyable协议)
foo("abc")
foo("")
十四.唯类协议
1. Swift还支持定义一种唯类协议,这种协议**只能被类实现,不能被枚举、结构体实现,如果程序中使用枚举、结构体实现唯类协议,编译器会报错。
2.定义唯类协议非常简单,只要在定义协议的协议名后面的冒号后面紧跟class关键字即可(class放在所有父协议的第一位):
protocol协议名:class,父协议1,父协议2,...
{
//唯类协议的定义。
}
3.唯类协议中无须定义mutating方法(定义了也没用,因为只有类才能实现唯类协议,类的方法本身就可以修改实例属性),除此之外,唯类协议与普通协议基本相同。
4.使用唯类协议的优势在于:Swift总是将唯类协议当成引用类型处理,而不会当成值类型处理。这是因为唯类协议的实现者只能是类,因此肯定是引用类型。
5.举个栗子:
protocol Movable : class
{
func move()
}
class Car : Movable
{
func move()
{
print("move in car")
}
}
struct Bee : Movable----这里将会报错
{
func move()
{
print("move in bee")
}
}
var move : Movable? = nil
上面的代码中,由于Movable是一个唯类协议,因此系统可以直接将move变量当成引用类型处理。
网友评论