比较两个`switch语句中的任何`,如果它们符合`Equatable`协议

时间:2016-03-10 12:56:48

标签: swift

我想做这样的事情:

func match(firstAny: Any, _ secondAny: Any) -> Bool {
    switch (firstAny, secondAny) {
        case (let first as Equatable, second as Equatable):
            return first == second
        case (let first as AnyObject, second as AnyObject):
            return first === second
        default:
            return false
    }
}

但我不能使用Equatable类型的情况。如何解决它?

1 个答案:

答案 0 :(得分:3)

成为Equatable并不意味着您可以将==应用于其他所有Equatable,因此这不起作用。 Equatable类型只能等同于它们自己的类型。因此,即使Swift可以做到这一点,你的方法也是错误的。您需要确保这两种类型具有相同的Self(在存在子类时有些复杂)。

有一些方法可以获得类似的重载,但我发现它们非常脆弱。例如:

func match<Eq: Equatable>(first: Eq, _ second: Eq) -> Bool {
    return first == second
}

func match(first: AnyObject, _ second: AnyObject) -> Bool {
    return first === second
}

func match(first: Any, _ second: Any) -> Bool {
    return false
}

这可以在非常有限的情况下工作,但是如果编译器无法在编译时证明类型是Equatable(并且在很多情况下理论上它可以证明它,但事实上它确实如此不),然后你会调用错误的函数。调试它真的很痛苦。

几乎所有情况下的答案都是重新设计你的系统而不需要这个,通常是通过处理你的程序实际需要的类型,而不是试图为每种可能的类型解决它。使事物过于通用是Swift中的常见问题;你击中了Swift无法实际处理的所有尖锐边缘。我从未见过这些解决方案可靠地工作。

(值得注意的是,如果match可以简单地实现而且没有奇怪的角落案例,那么stdlib几乎肯定会以这种方式实现==。事实==没有以这种方式工作是一个强烈的建议,它是一个比Swift中出现的问题复杂得多的问题。偶尔stdlib是错误的,但通常情况就是这样,如果你发现自己添加了“明显”缺失的部分,它可能会有惊喜。我已经多次烧过自己......)