我确实有 2 个不同类型的元组(Double、Double):
let tuple1: (Double, Double) = (1, 2)
let tuple2: (Double, Double) = (3, 4)
我想使用一个简单的 if 语句来比较它们的值。比如:
if (tuple1 == tuple2) {
// Do stuff
}
这会引发以下错误:
找不到接受提供的“==”重载 争论
我当前的解决方案是这样的函数:
func compareTuples <T: Equatable> (tuple1: (T, T), tuple2: (T, T)) -> Bool {
return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
}
我已经尝试编写一个扩展,但无法使其适用于元组。对于这个问题你有更优雅的解决方案吗?
更新
正如 Martin R 在评论中所述,现在可以将最多包含六个组件的元组与
==
进行比较。具有不同组件数量或不同组件类型的元组被认为是不同的类型,因此无法比较它们,但我下面描述的简单情况的代码现在已过时。
试试这个:
func == <T:Equatable> (tuple1:(T,T),tuple2:(T,T)) -> Bool
{
return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
}
和你的一模一样,但我叫它
==
。然后是这样的事情:
(1, 1) == (1, 1)
是真的并且
(1, 1) == (1, 2)
都是假的
我同意这种行为不是预期的,因为元组可以在不同的语言(例如Python和Haskell)中进行比较,但是根据官方文档:
注意
元组对于相关值的临时组很有用。他们不是 适合创建复杂的数据结构。如果你的数据 结构可能会持续超出临时范围,将其建模为 类或结构,而不是元组。有关更多信息,请参阅 类和结构。
因此,这可能在 Swift 中相当于“你拿错了手机”,但根据当前的指导方针,执行此操作的惯用方法是定义一个类或结构体(甚至是一个枚举),并提供一个可比较的实现来提供
==
以及相关运营商。
Swift 4 支持元组比较。您将不会再收到错误。
这段代码运行完美
let tuple1 : (Double, Double) = (1,2)
let tuple2 : (Double, Double) = (3,4)
if (tuple1 == tuple2) {
print("equal")
}
else {
print("unequal")
}
这里,unequal 被打印在游乐场的控制台中。
苹果文档中提到的元组比较的一个限制是 -
Swift 标准库包含元组比较运算符 元素少于七个的元组。将元组与七个或 更多元素,您必须自己实现比较运算符。
Swift 中存在我们所知的元组。元组可以使用标准 C 运算符进行相互比较。元组从左到右相互比较
if (1,"death") < (3,"life") {
print("Life is better than death") // this is true
}
Swift 只比较整数值 1 和 3。就是这样,Swift 不比较死亡和生命的字符串。仅当元组的第一个元素相同时才会比较它们。
if (99,"life") < (99,"death") {
print("Life is better than death") // this is false
}
在上面的例子中,swift 不会比较 99 的整数值,而是比较生与死。另外:Swift 只能比较最多有 6 个元素的元组。超过6个元素就得自己比较了。
与@JeremyP的答案类似,但更通用:
func ==<T1: Equatable, T2: Equatable>(lhs: (T1, T2), rhs: (T1, T2)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1
}
func ==<T1: Equatable, T2: Equatable, T3: Equatable>(lhs: (T1, T2, T3), rhs: (T1, T2, T3)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1 && lhs.2 == rhs.2
}
func ==<T1: Equatable, T2: Equatable, T3: Equatable, T4: Equatable>(lhs: (T1, T2, T3, T4), rhs: (T1, T2, T3, T4)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1 && lhs.2 == rhs.2 && lhs.3 == rhs.3
}
以下方法比较任意数量、任意大小的成员的元组,前提是它们不包含
Array
和 Dictionary
等集合类型。
import Darwin // or Foundation
/// here we go
func memeq<T>(var lhs: T, var rhs: T) -> Bool {
return withUnsafePointers(&lhs, &rhs) {
memcmp($0, $1, UInt(sizeof(T)))
} == 0
}
let l = (false, 42, log(exp(1.0)))
let r = (!true, 6*7, exp(log(1.0)))
println(memeq(l, r)) // expectedly true
let l2 = (0, [0])
let r2 = (0, [0])
println(memeq(l2, r2)) // unfortunately false
注释类型已通过泛型进行检查。如果它们不同,由于类型检查,它甚至无法编译。
此解决方案基于我之前的答案如何比较“任何”值类型,但包括任何类型的任意数量的项目的元组比较:
fileprivate extension Equatable {
func isEqual(to: Any) -> Bool {
self == to as? Self
}
}
func ==<T>(lhs: T?, rhs: T?) -> Bool where T: Any {
guard let lhs, let rhs else {
return lhs == nil && rhs == nil
}
// Equatable
if let isEqual = (lhs as? any Equatable)?.isEqual {
return isEqual(rhs)
}
// [Any]
else if let lhs = lhs as? [Any], let rhs = rhs as? [Any], lhs.count == rhs.count {
return lhs.elementsEqual(rhs, by: ==)
}
// [AnyHashable: Any]
else if let lhs = lhs as? [AnyHashable: Any], let rhs = rhs as? [AnyHashable: Any], lhs.count == rhs.count {
return lhs.allSatisfy { $1 == rhs[$0] }
}
// (Any...)
else {
let ml = Mirror(reflecting: lhs)
let mr = Mirror(reflecting: rhs)
guard ml.children.count == mr.children.count else {
return false
}
return zip(ml.children, mr.children).allSatisfy { $0.value == $1.value }
}
}
例如:
let t1 = (1, "2", 3.0, ["4" : 5], 6..<7, 8, [9, 10])
let t2 = (1, "2", 3.0, ["4" : 5], 6..<7, 8, [9, 10])
t1 == t2