swift - 在 Swift 的通用结构上实现 Equatable 的奇怪行为

标签 swift generics

import Foundation

struct NotEquable {}

struct Box<T> {
    let id: Int
    let value: T
}

extension Box: Equatable {
    static func ==<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

infix operator ====: AdditionPrecedence
public protocol OperatorEqual {
    static func ====(lhs: Self, rhs: Self) -> Bool
}

extension Box: OperatorEqual {
    static func ====<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ====<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

public protocol MethodStyleEquatable {
    static func equal(lhs: Self, rhs: Self) -> Bool
}

extension Box: MethodStyleEquatable {
    static func equal<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func equal<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

func freeEqual<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
    return lhs.id == rhs.id
}

func freeEqual<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
    return lhs.id == rhs.id && lhs.value == rhs.value
}

let a = Box(id: 1, value: 1)
let b = Box(id: 1, value: 2)
a == b
a ==== b
freeEqual(lhs: a, rhs: b)
Box<Int>.equal(lhs: a, rhs: b)

let c = Box(id: 1, value: NotEquable())
let d = Box(id: 1, value: NotEquable())
c == d
c ==== d
freeEqual(lhs: c, rhs: d)
Box<NotEquable>.equal(lhs: c, rhs: d)

在上面的代码片段中,Equatable有4种实现:默认实现、自定义操作符风格、方法风格和自由函数风格。我发现在默认或自定义情况下使用运算符样式总是会调用 equal 函数的通用版本。另一方面,使用方法或自由函数风格将根据 T 是否符合 Equatable 调用正确的版本。这是一个错误,或者我怎样才能使通用结构正确地符合 Equatable

最佳答案

您将类的泛型参数与等式函数的泛型参数混淆了。如所写,您的代码等同于:

struct Box<T1> {
    let id: Int
    let value: T1
}

extension Box: Equatable {
    static func ==<T2>(lhs: Box<T2>, rhs: Box<T2>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ==<T3: Equatable>(lhs: Box<T3>, rhs: Box<T3>) -> Bool {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

将您的定义更改为:

extension Box : Equatable {
    static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }
}

extension Box where T: Equatable {
    static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

它按预期工作。

关于swift - 在 Swift 的通用结构上实现 Equatable 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40713057/

相关文章:

swift - 点击手势事件不适用于 UIView

ios - 即使调用 needforlayout() ,单独类中的动画自动布局约束也会引发错误

java - 泛型和 Ormlite

c# - 派生类型和泛型

scala - 如何在不发出警告的情况下匹配未知的泛型类型

ios - UISwipeGestureRecognizer 抛出无法识别的选择器发送错误

ios - 未显示 UIButton 标题太长的省略号

ios - SKAction Moveto 没有在持续时间内完成?

java - 无法将通用项实例化为列表 Java

java - 为什么 Java 编译器知道你想对数组做什么,但不知道你想对泛型做什么?