Swift 之被忽视的角落:协议方法的静态派发与动态派发
2023-12-27 14:47:37
协议方法的静态派发与动态派发
静态派发
静态派发是在编译时确定方法的实现。这意味着编译器可以根据调用方法的对象的类型来确定要调用的方法的实现。静态派发通常用于那些不需要在运行时改变行为的方法,例如计算一个对象的面积或周长。
动态派发
动态派发是在运行时确定方法的实现。这意味着编译器无法在编译时确定要调用的方法的实现,而是需要在运行时根据调用方法的对象的类型来确定。动态派发通常用于那些需要在运行时改变行为的方法,例如处理用户输入或与网络服务通信。
协议方法的派发方式
协议方法的派发方式根据协议的声明方式而有所不同。如果协议使用 class
声明,则其方法将被静态派发。如果协议使用 protocol
关键字声明,则其方法将被动态派发。
示例
为了更好地理解协议方法的静态派发和动态派发之间的区别,我们来看一个示例。假设我们有一个 Shape
协议,它定义了两个方法:area()
和 perimeter()
。
protocol Shape {
func area() -> Double
func perimeter() -> Double
}
现在,我们有两个类 Circle
和 Square
,它们都遵循 Shape
协议。
class Circle: Shape {
var radius: Double
init(radius: Double) {
self.radius = radius
}
func area() -> Double {
return Double.pi * radius * radius
}
func perimeter() -> Double {
return 2 * Double.pi * radius
}
}
class Square: Shape {
var sideLength: Double
init(sideLength: Double) {
self.sideLength = sideLength
}
func area() -> Double {
return sideLength * sideLength
}
func perimeter() -> Double {
return 4 * sideLength
}
}
现在,我们创建一个 Shape
数组,并向其中添加一个 Circle
对象和一个 Square
对象。
var shapes: [Shape] = []
shapes.append(Circle(radius: 5.0))
shapes.append(Square(sideLength: 10.0))
现在,我们可以使用一个 for
循环来遍历 shapes
数组,并调用每个对象的 area()
和 perimeter()
方法。
for shape in shapes {
print("Area: \(shape.area())")
print("Perimeter: \(shape.perimeter())")
}
输出:
Area: 78.53981633974483
Perimeter: 31.41592653589793
Area: 100.0
Perimeter: 40.0
在这个示例中,area()
和 perimeter()
方法都被动态派发。这意味着编译器无法在编译时确定要调用的方法的实现,而是需要在运行时根据调用方法的对象的类型来确定。
总结
协议方法的派发方式根据协议的声明方式而有所不同。如果协议使用 class
关键字声明,则其方法将被静态派发。如果协议使用 protocol
关键字声明,则其方法将被动态派发。
静态派发通常用于那些不需要在运行时改变行为的方法,例如计算一个对象的面积或周长。动态派发通常用于那些需要在运行时改变行为的方法,例如处理用户输入或与网络服务通信。