swift中的Equatable协议

时间:2018-06-09 12:11:19

标签: swift generics protocols

我正在努力制作一个简单的游戏实现。所以每个游戏都有正确的答案。答案可以是Int或String。所以我在代码中有:

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

protocol CorrectAnswer {
    var correctAnswer: Answer { get }
}

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

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
    }
}

如果我想添加另一种答案类型(让我们说一堆Ints)我必须这样做:

extension Array: Answer where Element == Int {}

但困扰我的是在Equatable func的实现中= =我必须覆盖这个以及可能的其他情况。哪个可以戏剧化:)

是否有解决方案,可以更优雅和通用的方式完成吗?

1 个答案:

答案 0 :(得分:1)

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

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代替a 协议,并使 <{em> 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])
}

没有任何额外的代码。