如何在Swift 4.2中获得枚举的下一个例子(即写一个循环方法)

Swift 4.2引入了一个新的CaseIterable协议,它自动生成枚举中所有情况的数组属性.
现在我想实现Enum的默认方法继承自CaseIterable,它可以返回给定案例的下一个案例.如果这种情况是最后一种情况,请返回第一种情况.像一个圆圈.
如果我为特定的Enum写这个,它可以正常工作:

enum Direction: CaseIterable {
  case east, south, west, north

  func next() -> Direction {
    let all = type(of: self).allCases // 1
    if self == all.last! {
      return all.first!
    } else {
      let index = all.firstIndex(of: self)!
      return all[index + 1]
    }
  }
}

print(Direction.east.next()) // south  
print(Direction.north.next()) // east

但我想对许多Enum实现这个功能.重复复制和粘贴代码并不好(更不用说这个代码对于每个枚举都是完全相同的).
所以我尝试了这个.但出了点问题.
(我建议你将以下代码复制到游乐场,以便更快地理解这个问题):

extension CaseIterable {
  func next() -> Self {
    let all = type(of: self).allCases // 1
    if self == all.last { // 2
      return all.first!
    } else {
      let index = all.firstIndex { (ele) -> Bool in
        self == ele // 3
      }
      return all[index + 1]
    }
  }
}

三点:

>所有类型都是Self.AllCases,这是一种集合类型.但是在上面的方法中,它是[Direction].
>第2行出现错误,说’Self.AllCases’类型的值没有成员’last’
(即使我避免使用最后一次,也无法避免第3行的错误.)
>在第3行,错误是二元运算符’==’不能应用于两个’Self’操作数

甚至我使用通用约束,它也是一样的.

func next<T: CaseIterable>(element: T) -> T {...}

有解决方案吗:)

您的方法存在一些问题:

> Collection协议未定义最后一个属性.
>为了将元素与==进行比较,它们必须是Equatable.
>集合索引不一定是整数,它们必须递增
索引(后:).

这似乎是一个有效的解决方案(使用Xcode 10.0 beta 2测试):

extension CaseIterable where Self: Equatable {
    func next() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return all[next == all.endIndex ? all.startIndex : next]
    }
}

例:

enum Direction: CaseIterable {
    case east, south, west, north
}

print(Direction.east.next()) // south
print(Direction.north.next()) // east

备注:

>只有没有关联值的枚举才是CaseIterable,和那些也是Equatable(但编译器并没有弄明白通过它自己).因此Self:Equatable不是真正的限制.>可以在Swift 4.2中使用Self.allCases来访问type属性来自实例方法.>强制解包是安全的,因为我们知道价值是allCases的一个元素.>你的枚举方向:CaseIterable编译,因为具体枚举方向类型是Equatable,它的Direction.allCases是一个数组 – 它有整数索引和最后一个属性.

相关文章
相关标签/搜索