Swift 协议和扩展,我需要根据需要调用覆盖方法或默认扩展方法
Swift protocol and extension, I need to call overridden method or default extension method as per requirement
我有一个协议 Vehicle 及其扩展如下:
protocol Vehicle {
func Drive()
}
extension Vehicle {
func Stop() {
print("iiiich...")
}
}
我也有像下面这样的停止方法声明
struct Car: Vehicle {
func Drive() {
print("Can Drive")
}
func Stop() {
print("yo stop")
}
}
let myCar = Car()
myCar.Drive()
myCar.Stop()
但是它覆盖了停止方法
// Output
// Can Drive
// yo stop
并且根据我的要求,我有时需要默认方法,有时需要重写方法定义
如果需要在协议扩展中声明的方法,只需要让编译器认为汽车是Vehicle
:
类型即可
let myCar = Car()
(myCar as Vehicle).Stop()
嘿,我得到的答案是通过对象调用你的默认方法而不是覆盖来符合协议,所以我们可以根据需要调用这两个定义
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..
当我们创建一个没有类型的变量时,当对象仅符合协议时,这是静态分派。
正如答案中已经提到的,通用解决方案是确保调用 Stop()
方法的实例是 Vehicle
类型(而不是 Car
)。不过我想提一下这背后的逻辑是什么。
就个人而言,我认为在使用 POP 范式时可能会遇到这个问题。协议扩展是在我们的代码中应用 多态性 的一种便捷方式,但它确实会导致这种 "weird" 行为!
静态调度:
首先,请记住它不是一个错误。如果是:
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
手动将honda
转换为Vehicle
,此时编译器将使用static dispatch,这意味着在编译期间可以识别应该调用哪个方法(Vehicle().Stop
或 Car().Stop
)。它选择在扩展中实现的 Vehicle
的默认实现,而不需要检查具体类型是什么。
动态调度:
如果是:
let myCar = Car()
myCar.Drive()
myCar.Stop()
这里没有什么特别的,它完全符合预期。这正是 dynamic dispatch 的意思,导致应用 polymorphic 操作期间运行次。
为了更清楚,假设您有另一种类型符合 Vehicle
协议:
struct Bus: Vehicle {
func Drive() {
print("Bus Drive")
}
func Stop() {
print("Bus stop")
}
}
let myBus = Bus()
myCar.Drive()
myCar.Stop()
显然,print("Bus stop")
是将被调用的那个,实际上这是预期的!编译器 "smart" 足以根据具体类型 (Bus().Stop
) 识别要选择的方法。
此外:
为了更好地了解这里发生的事情,查看 Understanding Swift Performance Apple 会话可能会有所帮助。
您需要一个具有默认实现的协议,该协议允许结构参数,可以执行自定义行为:
import UIKit
struct Car{
//Any properties
func drive(){
print("Yo Drive")
}
func stop(){
print("Yo Stop")
}
}
protocol Vehicle {
func drive(vehicle : Car?)
func stop(vehicle : Car?)
}
extension Vehicle where Self: UIViewController {
func drive(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.drive()
}else{
print("drive default behavior")
}
}
func stop(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.stop()
}else{
print("stop default behavior")
}
}
}
class ViewController : UIViewController, Vehicle {
func driving() {
drive() //will print drive default behavior
stop() //will print stop default behavior
let car = Car()
drive(vehicle: car) //will print yo drive!
stop(vehicle: car) //will print yo Stop!
}
override func viewDidLoad() {
driving()
}
}
我有一个协议 Vehicle 及其扩展如下:
protocol Vehicle {
func Drive()
}
extension Vehicle {
func Stop() {
print("iiiich...")
}
}
我也有像下面这样的停止方法声明
struct Car: Vehicle {
func Drive() {
print("Can Drive")
}
func Stop() {
print("yo stop")
}
}
let myCar = Car()
myCar.Drive()
myCar.Stop()
但是它覆盖了停止方法
// Output
// Can Drive
// yo stop
并且根据我的要求,我有时需要默认方法,有时需要重写方法定义
如果需要在协议扩展中声明的方法,只需要让编译器认为汽车是Vehicle
:
let myCar = Car()
(myCar as Vehicle).Stop()
嘿,我得到的答案是通过对象调用你的默认方法而不是覆盖来符合协议,所以我们可以根据需要调用这两个定义
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..
当我们创建一个没有类型的变量时,当对象仅符合协议时,这是静态分派。
正如答案中已经提到的,通用解决方案是确保调用 Stop()
方法的实例是 Vehicle
类型(而不是 Car
)。不过我想提一下这背后的逻辑是什么。
就个人而言,我认为在使用 POP 范式时可能会遇到这个问题。协议扩展是在我们的代码中应用 多态性 的一种便捷方式,但它确实会导致这种 "weird" 行为!
静态调度:
首先,请记住它不是一个错误。如果是:
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
手动将honda
转换为Vehicle
,此时编译器将使用static dispatch,这意味着在编译期间可以识别应该调用哪个方法(Vehicle().Stop
或 Car().Stop
)。它选择在扩展中实现的 Vehicle
的默认实现,而不需要检查具体类型是什么。
动态调度:
如果是:
let myCar = Car()
myCar.Drive()
myCar.Stop()
这里没有什么特别的,它完全符合预期。这正是 dynamic dispatch 的意思,导致应用 polymorphic 操作期间运行次。
为了更清楚,假设您有另一种类型符合 Vehicle
协议:
struct Bus: Vehicle {
func Drive() {
print("Bus Drive")
}
func Stop() {
print("Bus stop")
}
}
let myBus = Bus()
myCar.Drive()
myCar.Stop()
显然,print("Bus stop")
是将被调用的那个,实际上这是预期的!编译器 "smart" 足以根据具体类型 (Bus().Stop
) 识别要选择的方法。
此外:
为了更好地了解这里发生的事情,查看 Understanding Swift Performance Apple 会话可能会有所帮助。
您需要一个具有默认实现的协议,该协议允许结构参数,可以执行自定义行为:
import UIKit
struct Car{
//Any properties
func drive(){
print("Yo Drive")
}
func stop(){
print("Yo Stop")
}
}
protocol Vehicle {
func drive(vehicle : Car?)
func stop(vehicle : Car?)
}
extension Vehicle where Self: UIViewController {
func drive(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.drive()
}else{
print("drive default behavior")
}
}
func stop(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.stop()
}else{
print("stop default behavior")
}
}
}
class ViewController : UIViewController, Vehicle {
func driving() {
drive() //will print drive default behavior
stop() //will print stop default behavior
let car = Car()
drive(vehicle: car) //will print yo drive!
stop(vehicle: car) //will print yo Stop!
}
override func viewDidLoad() {
driving()
}
}