实现相同协议的不同结构的重载函数?

Overload Functions For Different Structs Implementing The Same Protocol?

我是静态类型语言的新手,想知道是否可以将 Struct 转换为其类型以调用正确的重载函数?我 运行 遇到的问题是我有一个符合 Mutation 协议的结构列表。我想遍历列表并为每个 Struct 调用正确的 handle 函数。我可以将这个 handle 函数移动到 Struct 本身,但是对于我正在尝试实现的 API 我想看看这样的事情是否可行,如下所示:

//: Playground - noun: a place where people can play

import UIKit

protocol Mutation {
    func mutate(state: Int) -> Int
}

struct CountIncrement: Mutation {
    func mutate(state: Int) -> Int {
        return state + 1
    }
}

struct CountDecrement: Mutation {
    func mutate(state: Int) -> Int {
        return state - 1
    }
}

func handle(mutation: CountIncrement, state: Int) -> Int {
    print("WILL INCREMENT")
    return mutation.mutate(state: state)
}

func handle(mutation: CountDecrement, state: Int) -> Int {
    print("WILL DECREMENT")
    return mutation.mutate(state: state)
}

var state = 0
var queue = [CountIncrement(), CountDecrement()] as [Mutation]

for mutation in queue {
    handle(mutation: mutation, state: state) // error: cannot invoke 'handle' with an argument list of type '(mutation: Mutation, state: Int)'
}

您可以像这样组合您的 handle() 函数并接受参数 mutation 所有符合您的协议的对象 Mutation:

func handle(mutation: Mutation, state: Int) -> Int {
    return mutation.mutate(state: state)
}

这样做的原因:

queue 属于 [Mutating] 类型。因此,您的 for 循环中的 mutation 将是 Mutation。目前,您没有接受 Mutation 作为参数的 handle() 函数。

这与您解决问题的方式背道而驰。在 Swift 中,您通常应该避免自由函数(如 handle(mutation:state:)),而是将方法附加到类型。

你的循环需要一个特定的方法,所以你需要一个新的协议(你当然可以把这个函数附加到 Mutation,但是把它分开意味着它可以有不同的访问控制等等,所以和自由函数一样灵活)。

protocol MutationHandling {
    func handleMutation(forState state: Int) -> Int
}

所以我们刚刚宣布您想要的这个功能是一个东西。现在我们可以将它附加到我们关心的事物上。这与您上面编写的自由函数完全相同。这是相同的模式。语法只是不同,并提供了一些额外的文档说明为什么存在此函数,并允许 IDE 提供自动完成功能并更有效地收集文档。

extension CountIncrement: MutationHandling {
    func handleMutation(forState state: Int) -> Int {
        print("WILL INCREMENT")
        return mutate(state: state)
    }
}

现在,您将此特殊协议用于您的列表:

var queue = [CountIncrement(), CountDecrement()] as [MutationHandling]

并称它为:

for mutation in queue {
    mutation.handleMutation(forState: state)
}

这不仅仅是 Swift 中的一些随机限制。这是 Swift 如何分解问题的深层部分。明确不鼓励使用自由函数(参见 API Design Guidelines)。方法和扩展是 Swift 方式。