gpt4 book ai didi

swift - Swift 3中如何使用Mirror方便的实现 `isEqual`方法

转载 作者:可可西里 更新时间:2023-11-01 01:28:07 24 4
gpt4 key购买 nike

喜欢

class A :NSObject {
let a :Int
let b :UIColor
}

我不想通过一一比较所有属性来实现 isEqual。如果那样,当我添加另一个属性时,我应该再次修改 isEqual 的实现。

在 swift 中使用 Mirror 时,我可以方便地打印所有属性。如何使用Mirror方便的实现isEqual方法。

最佳答案

除了诊断之外,您不应该使用运行时内省(introspection),当然也不应该避免少量“样板”代码或避免更新现有代码。

然而,下面是关于该主题的一些评论,但请注意,这些应被视为 hack,不应在任何类型的生产代码中使用。但是,它们可以展示 Swift 中运行时内省(introspection)的一些示例用法。

Equatable class/struct“包装器”,使用运行时自省(introspection)进行逐个属性相等性测试

您可以实现一个 Equatable 容器来保存可等式类型的值,它可以(不同于 Equatable 本身)被转换为,我们将利用它来比较 classstruct 的属性。

/*  Heterogeneous protocol acts as castable Equatable container used for
property-by-property equality testing in EquatableConstruct */
protocol PseudoEquatableType {
func isEqual(to other: PseudoEquatableType) -> Bool
}

extension PseudoEquatableType where Self : Equatable {
func isEqual(to other: PseudoEquatableType) -> Bool {
if let o = other as? Self { return self == o }
return false
}
}

class/struct equatable“包装器”及其与Equatable 的一致性实现(ab)使用运行时自省(introspection):

/*  EquatableConstruct and its conformance to Equatable  */
protocol EquatableConstruct : Equatable { }
func ==<T: EquatableConstruct>(lhs: T, rhs: T) -> Bool {

let mirrorLhs = Mirror(reflecting: lhs)
let mirrorRhs = Mirror(reflecting: rhs)

guard let displayStyle = mirrorLhs.displayStyle,
(displayStyle == .struct || displayStyle == .class) else {

print("Invalid use: type is not a construct.")
return false
}

let childrenLhs = mirrorLhs.children.filter { $0.label != nil }
let childrenRhs = mirrorRhs.children.filter { $0.label != nil }

guard childrenLhs.count == childrenRhs.count else { return false }

guard !childrenLhs.contains(where: { !($0.value is PseudoEquatableType) }) else {
print("Invalid use: not all members have types that conforms to PseudoEquatableType.")
return false
}

return zip(
childrenLhs.flatMap { $0.value as? PseudoEquatableType },
childrenRhs.flatMap { $0.value as? PseudoEquatableType })
.reduce(true) { $0 && $1.0.isEqual(to: $1.1) }
}

示例用法

我们设置了一些非 native 类型以在示例中使用:

struct MyStruct {
var myInt: Int = 0
var myString: String = ""
}

class MyClass {
var myInt: Int
var myString: String
var myStruct: MyStruct
var myColor: UIColor

init(myInt: Int, myString: String,
myStruct: MyStruct, myColor: UIColor) {
self.myInt = myInt
self.myString = myString
self.myStruct = myStruct
self.myColor = myColor
}
}

对于某些给定的类型,例如MyClassEquatableConstruct“equatable wrapper”只有在类型本身(这里是MyClass)本身的所有类型的不同属性时才可以使用符合PseudoEquatableType:

/* Extend (some/all) fundamental (equatable) Swift types to PseudoEquatableType  */
extension Bool : PseudoEquatableType {}
extension Int : PseudoEquatableType {}
// ... Int8, UInt8, ..., Double, Float, ... and so on

extension String : PseudoEquatableType {}
extension UIColor: PseudoEquatableType {}

/* As a MyStruct instance is contained in MyClass, extend MyStruct to PseudoEquatableType
to add the type to allowed property types in EquatableConstruct */
extension MyStruct : PseudoEquatableType {}

/* Conformance to EquatableConstruct implies conformance to Equatable */
extension MyStruct : EquatableConstruct {}
extension MyClass : EquatableConstruct {}

测试 MyStructMyClass 的自动 Equatable 一致性,由它们与 EquatableConstruct 的一致性给出:

/* Example */
var aa = MyStruct()
var bb = MyStruct()

aa == bb // true
aa.myInt = 1
aa == bb // false

var a = MyClass(myInt: 10, myString: "foo",
myStruct: aa, myColor: UIColor(white: 1.0, alpha: 1.0))
var b = MyClass(myInt: 10, myString: "foo",
myStruct: aa, myColor: UIColor(white: 1.0, alpha: 1.0))

a == b // true
a.myInt = 2
a == b // false
b.myInt = 2
b.myString = "Foo"
a.myString = "Foo"
a == b // true
a.myStruct.myInt = 2
a == b // false
a.myStruct.myInt = 1
a == b // true
a.myColor = UIColor(white: 0.5, alpha: 1.0)
a == b // false

关于swift - Swift 3中如何使用Mirror方便的实现 `isEqual`方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40385864/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com