我有一个带有与此相关的值的枚举:
enum SomeState {
case loggedOut(redirectAfterLogin: Module? = nil)
case loggedIn
}
现在,在某些情况下,我想精确比较两个状态(例如都注销,并且重定向目标是否相等),有时我只想知道它们是否都注销了。我的问题与第二种情况有关:我想检查状态是否已注销并将其写入变量,但是显然我不能实现Equatable
来解决一般情况忽略参数。
一种实现此目的的方法是在Enum本身上实现一个计算属性isLoggedOut
,但是由于这里只是一个示例,而我的实际代码要大得多,因此这对我来说不是一个选择。 / p>
第二种方式(我当前使用的方式)是:
func whatever() {
if case .loggedOut = self.state {
self.isLoggedOut = true
} else {
self.isLoggedOut = false
}
}
这可行,但我宁愿这样写:
func whatever() {
self.isLoggedOut = (case .loggedOut = self.state)
}
我遗漏了一些东西吗,还是真的不可能直接将if
子句的大小写比较写成变量(或类似的单行解决方案)?
答案 0 :(得分:2)
您只需要将whatever
更改为计算属性而不是函数,将对isLoggedOut
的赋值修改为return
语句,便得到了{{1} }属性。
isLoggedOut
简化的示例代码,其中包含var isLoggedOut: Bool {
if case .loggedOut = self.state {
return true
} else {
return false
}
}
属性的类型也定义了state
属性:
isLoggedOut
答案 1 :(得分:1)
如何?
enum SomeState {
case loggedOut(redirectAfterLogin: Int? = nil)
case loggedIn
var isLoggedOut: Bool {
switch self {
case .loggedOut(_): return true
default: return false
}
}
}
var aState: SomeState = .loggedOut()
if aState.isLoggedOut {
print("logged out")
} else {
print("not logged out")
}
(我将关联的值redirectAfterLogin切换为简单的标量Int,因此它将为我们这些没有您的模块类型定义的人进行编译。您需要将其切换回。)
这里的窍门是计算所得的属性isLoggedOut,该属性使用switch语句忽略针对LoggedOut情况的关联值。
答案 2 :(得分:0)
我认为不可能避免在SomeState
之前使用.loggedOut
。即便如此,它还是比其他答案中的语言内置选项更好。
最好将Module
和SomeState
设为Equatable
,但这不是必须的。
public extension Mirror {
/// Get the associated value from an `enum` instance.
func getAssociatedValue<AssociatedValue>(
_: AssociatedValue.Type = AssociatedValue.self
) -> AssociatedValue? {
guard let childValue = children.first?.value
else { return nil }
if let associatedValue = childValue as? AssociatedValue {
return associatedValue
}
let labeledAssociatedValue = Mirror(reflecting: childValue).children.first
return labeledAssociatedValue?.value as? AssociatedValue
}
}
/// Match `enum` cases with associated values, while disregarding the values themselves.
/// - Parameter makeCase: Looks like `Enum.case`.
public func ~= <Enum: Equatable, AssociatedValue>(
makeCase: (AssociatedValue) -> Enum,
instance: Enum
) -> Bool {
Mirror(reflecting: instance).getAssociatedValue().map(makeCase)
== instance
}
/// Match `enum` cases with associated values, while disregarding the values themselves.
/// - Parameter makeCase: Looks like `Enum.case`.
public func ~= <Enum, AssociatedValue>(
makeCase: (AssociatedValue) -> Enum,
instance: Enum
) -> Bool {
let instanceMirror = Mirror(reflecting: instance)
guard let dummyCase = instanceMirror.getAssociatedValue().map(makeCase)
else { return false }
return
Mirror(reflecting: dummyCase).children.first?.label
== instanceMirror.children.first?.label
}
struct ? {
enum SomeState {
struct Module { }
case loggedOut(redirectAfterLogin: Module? = nil)
case loggedIn
}
var isLoggedOut: Bool
var state: SomeState
mutating func whatever() {
isLoggedOut = SomeState.loggedOut ~= state
}
}
更多用法示例:
enum ?: Equatable {
case tuple(cat: String, hat: String)
case labeled(cake: String)
case noAssociatedValue
}
let tupleCase = ?.tuple(cat: "?", hat: "?")
XCTAssertTrue(?.tuple ~= tupleCase)
XCTAssertTrue( ?.labeled ~= ?.labeled(cake: "?") )
let makeTupleCase = ?.tuple
XCTAssertFalse(makeTupleCase ~= ?.noAssociatedValue)
switch tupleCase {
case ?.labeled: XCTFail()
case makeTupleCase: break
default: XCTFail()
}