以下答案显示了一种可能的解决方案;可能不是推荐的(但可能对这个问题的未来读者感兴趣)。
如果您有大量属性都属于数量有限的不同类型,您可以使用Mirror
您的结构实例并迭代结构的属性;对于每次尝试转换为您知道您的属性的不同类型。
在观看了以下 WWDC 2015 会议(感谢 Leo Dabus!)之后,我编辑了之前的答案(我认为它更简洁):
我也会将最初的答案留在这个答案的底部,因为它显示了一种替代的、较少面向协议的方法来利用这个Mirror
解决方案。
Mirror
& 面向协议的解决方案:
/* Let a heterogeneous protocol act as "pseudo-generic" type
for the different (property) types in 'SuperStruct' */
protocol MyGenericType {
func isEqualTo(other: MyGenericType) -> Bool
}
extension MyGenericType where Self : Equatable {
func isEqualTo(other: MyGenericType) -> Bool {
if let o = other as? Self { return self == o }
return false
}
}
/* Extend types that appear in 'SuperStruct' to MyGenericType */
extension Int : MyGenericType {}
extension String : MyGenericType {}
extension Float : MyGenericType {}
// ...
/* Finally, 'SuperStruct' conformance to Equatable */
func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {
let mLhs = Mirror(reflecting: lhs).children.filter { $0.label != nil }
let mRhs = Mirror(reflecting: rhs).children.filter { $0.label != nil }
for i in 0..<mLhs.count {
guard let valLhs = mLhs[i].value as? MyGenericType, valRhs = mRhs[i].value as? MyGenericType else {
print("Invalid: Properties 'lhs.\(mLhs[i].label!)' and/or 'rhs.\(mRhs[i].label!)' are not of 'MyGenericType' types.")
return false
}
if !valLhs.isEqualTo(valRhs) {
return false
}
}
return true
}
示例用法:
/* Example */
var a = SuperStruct()
var b = SuperStruct()
a == b // true
a.field1 = 2
a == b // false
b.field1 = 2
b.field2 = "Foo"
a.field2 = "Foo"
a == b // true
以前的Mirror
解决方案:
/* 'SuperStruct' conformance to Equatable */
func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool {
let mLhs = Mirror(reflecting: lhs).children.filter { $0.label != nil }
let mRhs = Mirror(reflecting: rhs).children.filter { $0.label != nil }
for i in 0..<mLhs.count {
switch mLhs[i].value {
case let valLhs as Int:
guard let valRhs = mRhs[i].value as? Int where valRhs == valLhs else {
return false
}
case let valLhs as String:
guard let valRhs = mRhs[i].value as? String where valRhs == valLhs else {
return false
}
case let valLhs as Float:
guard let valRhs = mRhs[i].value as? Float where valRhs == valLhs else {
return false
}
/* ... extend with one case for each type
that appear in 'SuperStruct' */
case _ : return false
}
}
return true
}
示例用法:
/* Example */
var a = SuperStruct()
var b = SuperStruct()
a == b // true
a.field1 = 2
a == b // false
b.field1 = 2
b.field2 = "Foo"
a.field2 = "Foo"
a == b // true