让我们假设我们在 Swift中有一个非常大的结构: struct SuperStruct { var field1: Int = 0 var field2: String = "" // lots of lines... var field512: Float = 0.0} ..然后我们需要实现Equatable协议: extension SuperStru
struct SuperStruct { var field1: Int = 0 var field2: String = "" // lots of lines... var field512: Float = 0.0 }
..然后我们需要实现Equatable协议:
extension SuperStruct: Equatable { } func ==(lhs: SuperStruct, rhs: SuperStruct) -> Bool { return lhs.field1 == rhs.field1 && lhs.field2 == rhs.field2 && // lots of lines... lhs.field512 == rhs.field512 }
……我们需要编写许多愚蠢的代码行.
有没有办法“问”编译器为我们“做”它?
如果你有大量的属性都属于有限数量的不同类型,你可以使用结构实例的镜像并遍历结构的属性;每次尝试转换为您知道属性的不同类型.
在观看了以下WWDC 2015会议之后,我已经编辑了之前的答案(对于我认为非常整洁的东西)(感谢Leo Dabus!):
> WWDC 2015 session 408.推荐.
我将在这个答案的底部留下最初的答案,因为它显示了一种替代的,不那么面向协议的方法,以利用这个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
Previous 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