通过枚举迅速增加

时间:2018-02-04 19:20:31

标签: swift enums

我喜欢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()方法)。

6 个答案:

答案 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)

2020

只需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

以与编写所需部分相反的顺序:

  1. 采用协议。
extension CopyState: CircularCaseSequence { }
  1. 声明协议。
public protocol CircularCaseSequence:
  CaseIterable, Sequence, IteratorProtocol, Equatable
{ }

请注意此处的CaseIterable。如其他答案所示,即使CopyStateRawRepresentable,它也应该仍然是CaseIterable

  1. 符合Sequence
public extension CircularCaseSequence {
  mutating func next() -> Self? {
    self = offset(by: 1)
    return self
  }
}
  1. 允许个案抵消。
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]!
  }
}
  1. 允许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)]
    }
  }
}
  1. 允许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)
      )
    ]
  }
}
  1. 定义模数。
public extension BinaryInteger {
  func modulo(_ divisor: Self) -> Self {
    let remainder = self % divisor
    return
      remainder >= 0
      ? remainder
      : remainder + divisor
  }
}
相关问题