有没有办法检查泛型类型是否符合 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
)?
编译器正在按预期完成其工作。您声明的第二个方法独立于第一个方法,因此它不知道任何有关
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 {
}
阅读更多相关信息这里。
知道这是一个真正的老问题,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)
}