我一直在努力为枚举正确实施ForwardIndexType
协议,特别是最终案例的处理(即没有后继的最后一项)。 Swift语言书中没有涵盖这个协议。
这是一个简单的例子
enum ThreeWords : Int, ForwardIndexType {
case one=1, two, three
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
successor()
函数将返回下一个枚举器值,但最后一个元素除外,它将因异常而失败,因为在.three
之后没有值
ForwardTypeProtocol
不允许successor()
返回条件值,因此似乎无法发出信号表明没有后继者。
现在在for循环中使用它来迭代枚举的所有可能值的闭合范围,最终会遇到一个问题:
for word in ThreeWords.one...ThreeWords.three {
print(" \(word.rawValue)")
}
println()
//Crashes with the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
在执行for循环中的语句之前,Swift莫名其妙地调用范围结束值的successor()
函数。如果范围保持半开ThreeWords.one..<ThreeWords.three
,则代码正确执行,打印1 2
如果我修改后继功能,以便它不会尝试像这样创建大于.three
的值
func successor() ->ThreeWords {
if self == .three {
return .three
} else {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
然后for循环不会崩溃,但它也会错过最后一次迭代,打印时就好像范围是半开1 2
我的结论是swift的循环迭代中存在一个错误;它不应该在封闭范围的结束值上调用successor()
。其次,ForwardIndexType
应该能够返回一个可选的,以便能够发出某个值没有继承者的信号。
有没有人在这个协议上取得更多成功?
答案 0 :(得分:2)
答案 1 :(得分:2)
似乎是...
运营商
func ...<Pos : ForwardIndexType>(minimum: Pos, maximum: Pos) -> Range<Pos>
调用maximum.successor()
。它构建Range<T>
之类的
Range(start: minimum, end: maximum.successor())
因此,如果您想将enum
用作Range.Index
,则必须定义最后一个值的 next 。
enum ThreeWords : Int, ForwardIndexType {
case one=1, two, three
case EXHAUST
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1) ?? ThreeWords.EXHAUST
}
}
答案 2 :(得分:2)
这是一个古老的问题,但我想总结一些事情,并发布另一个可能的解决方案。
由于@jtbandes和@rintaro已经声明使用start...end
运算符创建的封闭范围是在内部使用start..<end.successor()
创建的
Afaik这是Swift中的故意行为。
在许多情况下,您还可以使用Interval
来考虑使用Range
或默认情况下Swift声明范围的地方。这里的要点是 interval 不是集合。
因此间隔
可能for word in ThreeWords.one...ThreeWords.three {...}
=====
对于以下内容,我假设上面的代码片段只是一个交叉检查值的调试案例。
要声明间隔,您需要明确指定类型。 HalfOpenInterval (..<)
或ClosedInterval (...)
var interval:ClosedInterval = ThreeWords.one...ThreeWords.four
这需要您进行枚举Comparable
。虽然Int
已经Comparable
,但仍需要将其添加到继承列表
enum ThreeWords : Int, ForwardIndexType, Comparable {
case one=1, two, three, four
func successor() ->ThreeWords {
return ThreeWords(rawValue:self.rawValue + 1)!
}
}
最后,枚举需要符合Comparable
。这是一种通用方法,因为您的枚举也符合协议RawRepresentable
func <<T: RawRepresentable where T.RawValue: Comparable>(lhs: T, rhs: T) -> Bool {
return lhs.rawValue < rhs.rawValue
}
就像我写的那样,你不能再循环遍历它了,但你可以使用开关进行快速交叉检查:
var interval:ClosedInterval = ThreeWords.one...ThreeWords.four
switch(ThreeWords.four) {
case ThreeWords.one...ThreeWords.two:
print("contains one or two")
case let word where interval ~= word:
print("contains: \(word) with raw value: \(word.rawValue)")
default:
print("no case")
}
打印“包含:四个原始值:4 ”