swift - swift 中的平等协议(protocol)

标签 swift generics protocols

我正在尝试制作一个简单的游戏实现。所以每场比赛都有一个正确的答案。 Answer 可以是 Int 或 String。所以我的代码是:

protocol Answer {}
extension Int: Answer {}
extension String: Answer {}

protocol CorrectAnswer {
    var correctAnswer: Answer { get }
}

我有一个游戏需要的协议(protocol):

protocol GameDescriber {
    var name: String { get }
    var description: String { get }
    var points: Int { get }
}

以及 Game 结构体的实现:

struct Game: GameDescriber, Equatable, CorrectAnswer {
    var correctAnswer: Answer
    var name: String
    var description: String
    var points: Int

    static func ==(_ lhs: Game, _ rhs:Game) -> Bool {
        if let _ = lhs.correctAnswer as? String, let _ = rhs.correctAnswer as? Int {
            return false
        }

        if let _ = lhs.correctAnswer as? Int, let _ = rhs.correctAnswer as? String {
            return false
        }

        if let lhsInt = lhs.correctAnswer as? Int, let rhsInt = rhs.correctAnswer as? Int {
            if lhsInt != rhsInt {
                return false
            }
        }

        if let lhsString = lhs.correctAnswer as? String, let rhsString = rhs.correctAnswer as? String {
            if lhsString != rhsString {
                return false
            }
        }

        return lhs.description == rhs.description &&
            lhs.name == rhs.name &&
            lhs.points == rhs.points
    }
}

如果我想添加另一种 Answer 类型(假设是 Ints 数组),我必须这样做:

extension Array: Answer where Element == Int {}

但令我困扰的是 Equatable func 的实现 == 我必须涵盖这种情况以及可能的其他情况。这让我很戏剧化:)

是否有针对此问题的解决方案,能否以更优雅和通用的方式完成?

最佳答案

首先请注意,== 的实现可以简化为

static func ==(_ lhs: Game, _ rhs:Game) -> Bool {
    switch (lhs.correctAnswer, rhs.correctAnswer) {
    case (let lhsInt as Int, let rhsInt as Int):
        if lhsInt != rhsInt {
            return false
        }
    case (let lhsString as String, let rhsString as String):
        if lhsString != rhsString {
            return false
        }
    default:
        return false
    }
    return lhs.description == rhs.description &&
        lhs.name == rhs.name &&
        lhs.points == rhs.points
}

这样添加另一种答案类型就意味着添加一个额外的 案例。

问题是编译器无法验证所有可能的 答案类型在你的 == 函数中处理,所以这种方法 很容易出错。

我实际上会做的是使用 enum Answer 而不是 协议(protocol),并使 that Equatable:

enum Answer: Equatable {
    case int(Int)
    case string(String)
}

请注意,您不必实现 ==。从 Swift 4.1 开始, 编译器自动合成,见 SE-0185 Synthesizing Equatable and Hashable conformance .

现在 Game 简化为

struct Game: GameDescriber, Equatable, CorrectAnswer {
    var correctAnswer: Answer
    var name: String
    var description: String
    var points: Int
}

编译器也合成 ==,默认实现比较所有存储的属性是否相等。

添加另一个答案类型只需将另一个案例添加到 枚举:

enum Answer: Equatable {
    case int(Int)
    case string(String)
    case intArray([Int])
}

没有任何额外的代码。

关于swift - swift 中的平等协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50774154/

相关文章:

Swift 静态属性初始化器是懒惰的,为什么我可以将它声明为常量

ios - iOS最小化应用程序时,如何每隔特定N天推送一次本地通知?

Java - 泛型类的类成员的行为

ios - UITableViewCell 中的约束不起作用

swift - 如何创建自定义 UIMenuController,仅包含默认项以外的自定义项?

.net - 为什么 resharper 建议 : "Return type can be IEnumerable<T>"?

java - 无法使用 Java 泛型将类型 int 转换为 E

http - HTTP/2 是无状态协议(protocol)吗?

swift - 实现通用协议(protocol)编译器错误

swift - 多个协议(protocol)扩展中的模糊函数?