我喜欢Swift允许使用枚举方法。我正在尝试使用一种方法,但我正在寻找一种更具扩展性的方法:
enum CopyState{
case binary, hex, both
init(){
self = .both
}
mutating func next() {
if self == .binary{
self = .hex
} else if self == .hex {
self = .both
} else if self == .both{
self = .binary
}
}
}
var state = CopyState()
state.next()
我想基本上将枚举转换为整数,并以模数总计枚举选项的模数递增
添加或删除枚举选项很麻烦(我使用的是last()和next()方法)。
答案 0 :(得分:8)
更新从Swift 4.2开始,您可以使用新添加的支持CaseIterable
协议,该协议增加了编译器支持,用于生成枚举的所有案例列表。然后你的枚举可能看起来像这样(不再是硬编码的起始值):
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]
}
}
或者,更加冗长,但更好地分离了关注点:
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)!
}
上面的代码不需要在第一个枚举案例更改时更新方法,但如果枚举的起始原始值发生更改,则可能会导致应用程序崩溃。
答案 1 :(得分:2)
快速doc说
使用存储整数或字符串原始值的枚举时 值,则不必为每种情况明确分配原始值。 不用时,Swift会自动为您分配值。
例如,当整数用于原始值时,隐式值 每一种情况都比前一种情况多。如果是第一种情况 没有设置值,值为0。
所以这很安全(Swift5)
enum CopyState: Int {
case binary, hex, both
mutating func next(){
self = CopyState(rawValue: rawValue + 1) ?? CopyState(rawValue: 0)!
}
}
答案 2 :(得分:0)
有时候我要做的是创建一个像这样的简单字典:
let copyStateDictionary = [
CopyState.binary: CopyState.hex,
CopyState.hex: CopyState.both,
CopyState.both: CopyState.binary
]
然后您可以使用以下方法“增加”变量:
state = copyStateDictionary[state]
也许可以通过编程的方式来生成此字典,而不是对其进行硬编码,但是如果它只有3-4个值,则可以进行硬编码。
答案 3 :(得分:0)
只需FTR,这就是@Cristik的绝妙答案,最新语法:
enum Fruits: CaseIterable {
case apple, banana, pitahaya, cherry
mutating func loopme() {
let a = type(of: self).allCases
self = a[(a.firstIndex(of: self)! + 1) % a.count]
}
}
答案 4 :(得分:0)
我在这里不会依靠CaseIterable
。 CaseIterable仅声明返回所有枚举值的集合,并且不对顺序做任何保证。
事实上,它确实按编码顺序返回了案例,这是一个实现细节,并且可能会更改无协议一致性。
但是,我会为案例明确分配int值:
next()
的逻辑。最近的是@Cristik的Int
支持的枚举。
enum CopyState: Int {
case binary = 0
case hex = 1
case both = 2
mutating func next() {
self = CopyState(rawValue: rawValue + 1) ?? .binary // or what ever should be the default
}
}
答案 5 :(得分:0)
您在这里得到的是一个“圆形案例序列”。你可以做到的! ?
这样做,您可以像以前一样从此开始……
enum CopyState {
case binary, hex, both
init() { self = .both }
}
...并能够执行以下操作:
var state = CopyState()
state.next() // binary
state.offset(by: -2) // hex
CopyState.allCases.elementsEqual( CopyState().prefix(3) ) // true
以与编写所需部分相反的顺序:
extension CopyState: CircularCaseSequence { }
public protocol CircularCaseSequence:
CaseIterable, Sequence, IteratorProtocol, Equatable
{ }
请注意此处的CaseIterable
。如其他答案所示,即使CopyState
是RawRepresentable
,它也应该仍然是CaseIterable
。
Sequence
。public extension CircularCaseSequence {
mutating func next() -> Self? {
self = offset(by: 1)
return self
}
}
public extension CaseIterable where Self: Equatable {
/// Another case from `allCases`.
///
/// Circularly wraps `offset` to always provide an element,
/// even when the resulting `index` is not valid.
func offset(by offset: Int) -> Self {
Self.allCases[self, moduloOffset: offset]!
}
}
Collection
元素进行偏移。public extension Collection where Element: Equatable {
/// Circularly wraps `index`, to always provide an element,
/// even when `index` is not valid.
subscript(
_ element: Element,
moduloOffset offset: Int
) -> Element? {
firstIndex(of: element).map {
self[modulo: index($0, offsetBy: offset)]
}
}
}
Collection
索引被包装。public extension Collection {
/// Circularly wraps `index`, to always provide an element,
/// even when `index` is not valid.
subscript(modulo index: Index) -> Element {
self[
self.index(
startIndex,
offsetBy:
distance(from: startIndex, to: index)
.modulo(count)
)
]
}
}
public extension BinaryInteger {
func modulo(_ divisor: Self) -> Self {
let remainder = self % divisor
return
remainder >= 0
? remainder
: remainder + divisor
}
}