在Swift 3.0中通过Enum迭代

Pha*_*m59 5 enums enumeration sequence swift

我有一个简单的枚举,我想迭代.为此,我采用了Sequence和IteratorProtocol,如下面的代码所示.顺便说一句,这可以复制/粘贴到Xcode 8中的Playground.

import UIKit

enum Sections: Int {
  case Section0 = 0
  case Section1
  case Section2
}

extension Sections : Sequence {
  func makeIterator() -> SectionsGenerator {
    return SectionsGenerator()
  }

  struct SectionsGenerator: IteratorProtocol {
    var currentSection = 0

    mutating func next() -> Sections? {
      guard let item = Sections(rawValue:currentSection) else {
        return nil
      }
      currentSection += 1
      return item
    }
  }
}

for section in Sections {
  print(section)
}
Run Code Online (Sandbox Code Playgroud)

但是for-in循环生成错误消息"Type'Sections.Type'不符合协议'Sequence'".协议一致性在我的扩展中; 那么,这段代码有什么问题?

我知道还有其他方法可以做到这一点,但我想了解这种方法有什么问题.

谢谢.

Jan*_*ano 10

请注意,Martin的解决方案可以重构为协议:

import Foundation

protocol EnumSequence
{
    associatedtype T: RawRepresentable where T.RawValue == Int
    static func all() -> AnySequence<T>
}
extension EnumSequence
{
    static func all() -> AnySequence<T> {
        return AnySequence { return EnumGenerator() }
    }
}

private struct EnumGenerator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
    var index = 0
    mutating func next() -> T? {
        guard let item = T(rawValue: index) else {
            return nil
        }
        index += 1
        return item
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,给出一个枚举

enum Fruits: Int {
    case apple, orange, pear
}
Run Code Online (Sandbox Code Playgroud)

你打了协议和一个typealias:

enum Fruits: Int, EnumSequence {
    typealias T = Fruits
    case apple, orange, pear
}

Fruits.all().forEach({ print($0) }) // apple orange pear
Run Code Online (Sandbox Code Playgroud)


Mar*_*n R 9

更新:从Swift 4.2开始,您可以简单地添加协议一致性CaseIterable,请参阅如何使用String类型枚举枚举?.


您可以迭代符合 协议的类型的Sequence.因此

for section in Sections.Section0 {
  print(section)
}
Run Code Online (Sandbox Code Playgroud)

会编译并给出预期的结果.但是当然这并不是你想要的,因为值的选择是任意的,序列中不需要值本身.

据我所知,没有办法迭代一个类型本身,所以

for section in Sections {
  print(section)
}
Run Code Online (Sandbox Code Playgroud)

编译.这将要求"元变型" Sections.Type符合Sequence.也许有人证明我错了.

你可以做的是定义一个返回序列的类型方法:

extension Sections {
    static func all() -> AnySequence<Sections> {
        return AnySequence {
            return SectionsGenerator()
        }
    }

    struct SectionsGenerator: IteratorProtocol {
        var currentSection = 0

        mutating func next() -> Sections? {
            guard let item = Sections(rawValue:currentSection) else {
                return nil
            }
            currentSection += 1
            return item
        }
    }

}

for section in Sections.all() {
    print(section)
}
Run Code Online (Sandbox Code Playgroud)


Сер*_*лык 5

只需添加到枚举: static var allTypes: [Sections] = [.Section0, .Section1, .Section2]

而且你可以:

Sections.allTypes.forEach { (section) in
            print("\(section)")
}
Run Code Online (Sandbox Code Playgroud)