[英]Compare Swift Enum types ignoring associated values - generic implementation
I have several different enums in my project, that conform to the same protocol. 我的项目中有几个不同的枚举,符合相同的协议。 The
compareEnumType
method from the protocol compares enum cases ignoring associated values. 协议中的
compareEnumType
方法比较忽略关联值的枚举情况。 Here is my code from playground: 这是我在游乐场的代码:
protocol EquatableEnumType {
static func compareEnumType(lhs: Self, rhs: Self) -> Bool
}
enum MyEnum: EquatableEnumType {
case A(Int)
case B
static func compareEnumType(lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.A, .A): return true
case (.B, .B): return true
default: return false
}
}
}
enum MyEnum2: EquatableEnumType {
case X(String)
case Y
static func compareEnumType(lhs: MyEnum2, rhs: MyEnum2) -> Bool {
switch (lhs, rhs) {
case (.X, .X): return true
case (.Y, .Y): return true
default: return false
}
}
}
let a = MyEnum.A(5)
let a1 = MyEnum.A(3)
if MyEnum.compareEnumType(lhs: a, rhs: a1) {
print("equal") // -> true, prints "equal"
}
let x = MyEnum2.X("table")
let x1 = MyEnum2.X("chair")
if MyEnum2.compareEnumType(lhs: x, rhs: x1) {
print("equal2") // -> true, prints "equal2"
}
In my real project I have more than 2 enums, and for each of them I have to have similar implementation of compareEnumType
function. 在我的真实项目中,我有两个以上的枚举,对于每个枚举,我必须有
compareEnumType
函数的类似实现。
The question is: is it possible to have a generic implementation of compareEnumType
which would work for all enums conforming to EquatableEnumType
protocol? 问题是:是否可以使用
compareEnumType
的通用实现,它适用于符合EquatableEnumType
协议的所有枚举?
I tried to write a default implementation in protocol extension like this: 我尝试在协议扩展中编写一个默认实现,如下所示:
extension EquatableEnumType {
static func compareEnumType(lhs: Self, rhs: Self) -> Bool {
// how to implement???
}
}
But I'm stuck with implementation. 但我坚持实施。 I don't see a way to access a value contained in
lhs
and rhs
. 我没有看到访问
lhs
和rhs
包含的值的方法。 Could anyone help me? 谁能帮助我?
I don't think that you can autogenerate this so here is a way using extensions. 我不认为你可以自动生成这个,所以这是一种使用扩展的方式。 I suggest to create a new
enum CompareEnumMethod
which tells if you want to compare the associated values
or only the type
. 我建议创建一个新的
enum CompareEnumMethod
,它告诉您是要比较关联的values
还是仅比较type
。 Create a new function compareEnum
in your protocol that has this enum as a parameter. 在您的协议中创建一个新函数
compareEnum
,该函数将此枚举作为参数。 Then, you can create an extension for ==(lhs:,rhs:)
and say that it uses .value
and for compareEnumType
you use .type
. 然后,您可以为
==(lhs:,rhs:)
创建一个扩展名,并说它使用.value
而对于compareEnumType
,则使用.type
。 Only the compareEnum
method has to be implemented in each enum now. 现在只需要在每个枚举中实现
compareEnum
方法。
enum CompareEnumMethod {
case type, value
}
protocol EquatableEnumType: Equatable {
static func compareEnumType(lhs: Self, rhs: Self) -> Bool
static func compareEnum(lhs: Self, rhs: Self, method: CompareEnumMethod) -> Bool
}
extension EquatableEnumType {
static func compareEnumType(lhs: Self, rhs: Self) -> Bool {
return Self.compareEnum(lhs: lhs, rhs: rhs, method: .type)
}
static func ==(lhs: Self, rhs: Self) -> Bool {
return Self.compareEnum(lhs: lhs, rhs: rhs, method: .value)
}
}
enum MyEnum: EquatableEnumType {
case A(Int)
case B
static func compareEnum(lhs: MyEnum, rhs: MyEnum, method: CompareEnumMethod) -> Bool {
switch (lhs, rhs, method) {
case let (.A(lhsA), .A(rhsA), .value):
return lhsA == rhsA
case (.A, .A, .type),
(.B, .B, _):
return true
default:
return false
}
}
}
let a0 = MyEnum.A(5)
let a1 = MyEnum.A(3)
let b0 = MyEnum.B
print(MyEnum.compareEnumType(lhs: a0, rhs: a1)) //true
print(a0 == a1) //false
print(MyEnum.compareEnumType(lhs: a0, rhs: b0)) //false
Easy! 简单! I would use an instance method, but you can rewrite it to a class function, if you really need it to be static.
我会使用一个实例方法,但你可以将它重写为类函数,如果你真的需要它是静态的。
extension EquatableEnumCase {
func isSameCase(as other: Self) -> Bool {
let mirrorSelf = Mirror(reflecting: self)
let mirrorOther = Mirror(reflecting: other)
if let caseSelf = mirrorSelf.children.first?.label, let caseOther = mirrorOther.children.first?.label {
return (caseSelf == caseOther) //Avoid nil comparation, because (nil == nil) returns true
} else { return false}
}
}
enum MyEnum1: EquatableEnumCase {
case A(Int)
case B
}
enum MyEnum2: EquatableEnumCase {
case X(String)
case Y
}
let a = MyEnum1.A(5)
let a1 = MyEnum1.A(3)
if a.isSameCase(as: a1) {
print("equal") // -> true, prints "equal1"
}
let x = MyEnum2.X("table")
let x1 = MyEnum2.X("chair")
if x.isSameCase(as: x1) {
print("equal2") // -> true, prints "equal2"
}
let y = MyEnum2.Y
print(x.isSameCase(as: y) ? "equal3": "not equal3") // -> false, "not equal3"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.