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
Run Code Online (Sandbox Code Playgroud)
但我想对许多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]
}
}
}
Run Code Online (Sandbox Code Playgroud)
三点:
all的类型是Self.AllCases,这是一种Collection类型.但是在上面的方法中,它是[Direction].Value of type 'Self.AllCases' has no member 'last'
(即使我避免使用last,也无法避免第3行的错误.)Binary operator '==' cannot be applied to two 'Self' operands甚至我使用通用约束,它也是一样的.
func next<T: CaseIterable>(element: T) -> T {...}
Run Code Online (Sandbox Code Playgroud)
有解决方案吗 :)
您的方法存在一些问题:
Collection协议没有定义last属性.==它们必须的元素Equatable.index(after:).这似乎是一个有效的解决方案(使用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]
}
}
Run Code Online (Sandbox Code Playgroud)
例:
enum Direction: CaseIterable {
case east, south, west, north
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
Run Code Online (Sandbox Code Playgroud)
备注:
CaseIterable,而且这些枚举也是Equatable(但编译器本身并未弄清楚).因此Self: Equatable不是一个真正的限制.Self.allCases 可以在Swift 4.2中使用从实例方法访问type属性.allCases.enum Direction: CaseIterable编译因为具体
enum Direction类型是Equatable,它Direction.allCases是一个Array- 它有整数索引和last属性.如果有人有兴趣到两个previous和next的情况下,这里是以前的答案的升级:
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
func previous() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let previous = all.index(before: idx)
return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
}
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]
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,您也不需要BidirectionalCollection一致性来实现previous案例。
extension CaseIterable where Self: Equatable {
func previous() -> Self {
let all = Self.allCases
var idx = all.firstIndex(of: self)!
if idx == all.startIndex {
let lastIndex = all.index(all.endIndex, offsetBy: -1)
return all[lastIndex]
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以制作更通用的循环偏移函数:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self {
let all = Array(Self.allCases)
let idx = (all.firstIndex(of: self)! + n) % all.count
print(idx)
if idx >= 0 {
return all[idx]
} else {
return all[all.count + idx]
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
522 次 |
| 最近记录: |