Swift 泛型 - 如果它们是 Equatable,则返回 equals,否则返回 nil

问题描述 投票:0回答:2

有没有办法检查泛型类型是否符合 Equatable ?我希望能够检查相同泛型类型的两个对象是否相等,或者相等对它们来说是否没有意义。

由于 Equatable 只能用作通用约束(因为它有 Self 或 AssociatedType 要求),我尝试过使用通用重载:

//If T is equatable, this is more specific so should be called
func equals<T:Equatable>(lhs:T, rhs:T) -> Bool?{
    return lhs == rhs
}

//This should only be called if T is not equatable at compile time
func equals<T>(lhs:T, rhs:T) -> Bool?{
    return nil
}

这在使用特定类型调用时有效,例如

equals(lhs:1, rhs:1)
按预期返回
true
。但是,如果在通用上下文中调用它,它总是返回
nil
:

func doSomethingThenCheckEquals<T>(lhs:T, rhs:T){
    //Do something here which has no type requirements

    //Check if the two objects are equal - would usually do something with the result
    //This will always use equals<T> and never equals<T:Equatable>, so will always be nil
    _ = equals(lhs:lhs, rhs:rhs) 
}

有什么方法可以达到预期的效果吗?

此外,根据这个答案,编译器从具有动态类型检查的单个实现开始,但在某些情况下可以创建专门的实现。如果编译器创建了一个专门的实现,它的行为是否与第一种情况类似(其中

equals(lhs:1, rhs:1)
返回
true
)?

swift generics
2个回答
0
投票

编译器正在按预期完成其工作。您声明的第二个方法独立于第一个方法,因此它不知道任何有关

T
的信息。

泛型是前向声明,这意味着我们需要告诉编译器它将遵循什么协议,然后编译器将采取所有必要的步骤来适应这一点。也许将来,我们可以期待函数调用级别的类型解释,但目前还没有可用。

func doSomethingThenCheckEquals<T>(lhs:T, rhs:T){
//Do something here which has no type requirements

   //Check if the two objects are equal - would usually do something with the result
   //This will always use equals<T> and never equals<T:Equatable>, so will always be nil
    _ = equals(lhs:lhs, rhs:rhs) 
}

最好的解决方案是使用

where
子句。

 func doSomethingThenCheckEqual<T>(lhs: T, rhs: T) where T:Equatable {


 }

阅读更多相关信息这里


0
投票

知道这是一个真正的老问题,Swift 已经改变了很多,但我来到这里试图找到答案,我想我会留下我找到的答案,以防其他人最终来到这里:

可以通过首先扩展 Equatable 来实现这一点(代码取自此处:https://nilcoalescing.com/blog/CheckIfTwoValuesOfTypeAnyAreEqual/

extension Equatable {
    func isEqual(_ other: any Equatable) -> Bool {
        guard let other = other as? Self else {
            return other.isExactlyEqual(self)
        }
        return self == other
    }
    
    private func isExactlyEqual(_ other: any Equatable) -> Bool {
        guard let other = other as? Self else {
            return false
        }
        return self == other
    }
}

然后在 equals 函数中尝试首先将它们都转换为

any Equatable

func equals<T>(lhs: T, rhs: T) -> Bool? {
    guard let left = lhs as? any Equatable, guard let right = rhs as? any Equatable else {
        return nil
    }

    return left.isEqual(right)
}
© www.soinside.com 2019 - 2024. All rights reserved.