Update从 Swift 4.2 开始,您可以利用新添加的支持CaseIterable
协议,它添加了编译器支持以生成枚举的所有情况的列表。虽然@ninestonescomment https://stackoverflow.com/questions/48612076/swift-increment-through-enum/48612152#comment108080020_48612152指出我们不能保证allCases
要以与定义相同的顺序返回案例,合成的实现会执行此操作,并且定义不太可能更改。
然后,您的枚举可能看起来像这样(不再有硬编码的起始值):
enum CopyState: CaseIterable {
case binary, hex, both
mutating func next() {
let allCases = type(of: self).allCases
self = allCases[(allCases.index(of: self)! + 1) % allCases.count]
}
}
您可以让所有人都可以使用此功能CaseIterable
enums:
extension CaseIterable where Self: Equatable {
mutating func next() {
let allCases = Self.allCases
// just a sanity check, as the possibility of a enum case to not be
// present in `allCases` is quite low
guard let selfIndex = allCases.index(of: self) else { return }
let nextIndex = Self.allCases.index(after: selfIndex)
self = allCases[nextIndex == allCases.endIndex ? allCases.startIndex : nextIndex]
}
}
enum CopyState: CaseIterable {
case binary, hex, both
}
var state = CopyState.hex
state.next()
print(state) // both
state.next()
print(state) // binary
或者,更详细一点,但更好地分离关注点:
extension Collection {
// adding support for computing indexes in a circular fashion
func circularIndex(after i: Index) -> Index {
let nextIndex = index(after: i)
return nextIndex == endIndex ? startIndex : nextIndex
}
}
extension Collection where Element: Equatable {
// adding support for retrieving the next element in a circular fashion
func circularElement(after element: Element) -> Element? {
return index(of: element).map { self[circularIndex(after: $0)] }
}
}
// Protocol to allow iterating in place (similar to a type conforming to both Sequence and IteratorProtocol)
protocol InPlaceIterable {
mutating func next()
}
extension InPlaceIterable where Self: CaseIterable, Self: Equatable {
// adding default implementation for enums
mutating func next() {
self = type(of: self).allCases.circularElement(after: self)!
}
}
// now the enums need only the protocol conformances, they get the
// functionalities for free
enum CopyState: CaseIterable, InPlaceIterable {
case binary, hex, both
}
你可以使用Int
作为枚举的原始值(请注意,如果您不指定它,这也是默认的原始值),并像这样使用它:
enum CopyState: Int {
case binary, hex, both
mutating func next(){
self = CopyState(rawValue: rawValue + 1) ?? .binary
}
}
var state = CopyState.hex
state.next()
print(state) // both
state.next()
print(state) // binary
只要您拥有连续顺序的枚举案例的原始值,这种方法就可以正常工作。默认情况下,编译器分配连续的原始值。
您还需要记住更新next()
方法如果第一种情况发生变化,否则它将不再正确工作。
@MartinR 建议的上述限制的替代方法是强制解开原始值零:
mutating func next(){
self = CopyState(rawValue: rawValue + 1) ?? CopyState(rawValue: 0)!
}
当第一个枚举情况发生更改时,上面的代码不需要更新方法,但是如果枚举的起始原始值发生更改,则可能会导致应用程序崩溃。