比较 Swift 中的两个协议实例是否相等
Comparing Two Protocol Instances for Equality in Swift
这是交易,
我正在编写一个 SDK,我想将观察者声明为协议,而不是 类 或结构(这是一种 "Observer/Delegate" 混合)。
我希望能够比较作为协议引用传入的两个参数,而不是具体 classes/structs 它们实际上是 IRL。
我知道 "easy" 进行比较的方法是将协议限制为 Hashable
或 Equatable
,但我想避免给用户带来负担(它是一个 SDK)。
这是我的意思的小操场:
protocol A {
func AFunc() -> String
}
class APrime: A {
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
func compareTypes(_ inA: A, _ inB: A) -> String {
// if inA == inB {
// return ""
// }
return "not "
}
print("A is \(compareTypes(variableA, variableB))B.")
print("A is \(compareTypes(variableA, variableA))A.")
不修边幅的部分是 compareTypes(_: A, _: A)
中被注释掉的部分。我需要弄清楚如何在不进入 "Hacksylvania," 的情况下比较它们,我可以通过在每个实例中比较 AFunc() 的地址来做到这一点。
预期输出为:
A is not B.
A is A.
关于更 "swifty" 方法的任何想法?我一定是只见树木不见森林。
只是为此添加一些关闭,这是我解决这个问题的方法:
protocol A {
var uuid: Int { get } // This is the secret sauce. It will contain a unique UUID, associated with the instance.
func AFunc() -> String
}
class APrime: A {
let uuid: Int = Int.random(in: 0..<1000) // The UUID is initialized with the instance.
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
let variableC = variableA
func compareTypes(_ inA: A, _ inB: A) -> String {
if inA.uuid == inB.uuid { // We compare UUIDs.
return ""
}
return "not "
}
print("C is \(compareTypes(variableC, variableB))B.")
print("C is \(compareTypes(variableC, variableA))A.")
"uuid"变量通常是一个实际的UUID类型,但我不想在示例中导入Foundation,所以我只是做了一个简单的rand。它明白了这一点。
这输出:
C is not B.
C is A.
还有另一种方法(我有时也用):
protocol B {
func BFunc() -> String
func amIThisOne(_ instanceToCompare: B) -> Bool // This is an identity comparator
}
class BPrime: B {
func BFunc() -> String { "I AM GROOT'S BROTHER" }
// We compare ourselves against the other instance, assuming it can be cast to our own type.
func amIThisOne(_ inInstanceToCompare: B) -> Bool {
guard let instanceToCompare = inInstanceToCompare as? Self else { return false }
return self === instanceToCompare
}
}
let variableD = BPrime()
let variableE = BPrime()
let variableF = variableD
print("D is \(variableE.amIThisOne(variableD) ? "" : "not ")E.")
print("D is \(variableD.amIThisOne(variableF) ? "" : "not ")F.")
输出:
D is not E.
D is F.
这允许以更编程的方式比较实例。
如何不这样做
然后,当然,如果我们控制了实例,我们就可以真正做到 Equatable 的事情(这需要 playground 导入 Foundation):
protocol C: Equatable {
func CFunc() -> String
}
class CPrime: C {
// This is actually not what I want, as I want to compare protocols, not conforming classes.
static func == (lhs: CPrime, rhs: CPrime) -> Bool {
guard let lhs = lhs as? Self else { return false }
guard let rhs = rhs as? Self else { return false }
return lhs === rhs
}
func CFunc() -> String { "I AM GROOT'S UDDER BROTHER" }
}
let variableG = CPrime()
let variableH = CPrime()
let variableI = variableG
print("G is \(variableG == variableH ? "" : "not ")H.")
print("G is \(variableI == variableG ? "" : "not ")I.")
输出:
G is not H.
G is I.
这是交易,
我正在编写一个 SDK,我想将观察者声明为协议,而不是 类 或结构(这是一种 "Observer/Delegate" 混合)。
我希望能够比较作为协议引用传入的两个参数,而不是具体 classes/structs 它们实际上是 IRL。
我知道 "easy" 进行比较的方法是将协议限制为 Hashable
或 Equatable
,但我想避免给用户带来负担(它是一个 SDK)。
这是我的意思的小操场:
protocol A {
func AFunc() -> String
}
class APrime: A {
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
func compareTypes(_ inA: A, _ inB: A) -> String {
// if inA == inB {
// return ""
// }
return "not "
}
print("A is \(compareTypes(variableA, variableB))B.")
print("A is \(compareTypes(variableA, variableA))A.")
不修边幅的部分是 compareTypes(_: A, _: A)
中被注释掉的部分。我需要弄清楚如何在不进入 "Hacksylvania," 的情况下比较它们,我可以通过在每个实例中比较 AFunc() 的地址来做到这一点。
预期输出为:
A is not B.
A is A.
关于更 "swifty" 方法的任何想法?我一定是只见树木不见森林。
只是为此添加一些关闭,这是我解决这个问题的方法:
protocol A {
var uuid: Int { get } // This is the secret sauce. It will contain a unique UUID, associated with the instance.
func AFunc() -> String
}
class APrime: A {
let uuid: Int = Int.random(in: 0..<1000) // The UUID is initialized with the instance.
func AFunc() -> String { "I AM GROOT" }
}
let variableA = APrime()
let variableB = APrime()
let variableC = variableA
func compareTypes(_ inA: A, _ inB: A) -> String {
if inA.uuid == inB.uuid { // We compare UUIDs.
return ""
}
return "not "
}
print("C is \(compareTypes(variableC, variableB))B.")
print("C is \(compareTypes(variableC, variableA))A.")
"uuid"变量通常是一个实际的UUID类型,但我不想在示例中导入Foundation,所以我只是做了一个简单的rand。它明白了这一点。
这输出:
C is not B.
C is A.
还有另一种方法(我有时也用):
protocol B {
func BFunc() -> String
func amIThisOne(_ instanceToCompare: B) -> Bool // This is an identity comparator
}
class BPrime: B {
func BFunc() -> String { "I AM GROOT'S BROTHER" }
// We compare ourselves against the other instance, assuming it can be cast to our own type.
func amIThisOne(_ inInstanceToCompare: B) -> Bool {
guard let instanceToCompare = inInstanceToCompare as? Self else { return false }
return self === instanceToCompare
}
}
let variableD = BPrime()
let variableE = BPrime()
let variableF = variableD
print("D is \(variableE.amIThisOne(variableD) ? "" : "not ")E.")
print("D is \(variableD.amIThisOne(variableF) ? "" : "not ")F.")
输出:
D is not E.
D is F.
这允许以更编程的方式比较实例。
如何不这样做
然后,当然,如果我们控制了实例,我们就可以真正做到 Equatable 的事情(这需要 playground 导入 Foundation):
protocol C: Equatable {
func CFunc() -> String
}
class CPrime: C {
// This is actually not what I want, as I want to compare protocols, not conforming classes.
static func == (lhs: CPrime, rhs: CPrime) -> Bool {
guard let lhs = lhs as? Self else { return false }
guard let rhs = rhs as? Self else { return false }
return lhs === rhs
}
func CFunc() -> String { "I AM GROOT'S UDDER BROTHER" }
}
let variableG = CPrime()
let variableH = CPrime()
let variableI = variableG
print("G is \(variableG == variableH ? "" : "not ")H.")
print("G is \(variableI == variableG ? "" : "not ")I.")
输出:
G is not H.
G is I.