switch 在递归类型中必须是详尽的
Posted
技术标签:
【中文标题】switch 在递归类型中必须是详尽的【英文标题】:switch must be exhaustive in Recursive type 【发布时间】:2019-10-30 16:17:23 【问题描述】:enum Tree<Element: Comparable>
case empty
indirect case node(Tree<Element>, Element, Tree<Element>)
func forEach(withLooping fn: (Element) -> Void)
var stack = [self]
while !stack.isEmpty
let current = stack.popLast()
switch current
case .empty: break
case let .node(left, value, right):
fn(value)
stack.append(left)
stack.append(right)
case .none: // !!!
break
Xcode 强制我添加.none
大小写,但.none
不是Tree
的构造函数
xxx.swift:9:7: error: switch must be exhaustive
switch current
^
xxx.swift:9:7: note: add missing case: '.none'
switch current
为什么?
【问题讨论】:
popLast()
返回Optional<Tree>
,它有.none
大小写。
【参考方案1】:
问题不在于枚举是递归的,而是popLast()
方法返回一个可选(如果数组为空,则为nil
)。因此current
的可能情况是
case .some(.empty):
case .some(.node(left, value, right)):
case .none: // Or equivalently: case nil:
从 Swift 5.1 开始,枚举案例可以与非可选枚举模式匹配(比较 SR-7799),因此这可以简化为
case .empty:
case .node(left, value, right):
case .none: // Or equivalently: case nil:
这解释了编译器错误和修复它。
但是,nil
的情况不会发生,因为您检查该数组是否为空。以下是三种可能的解决方案:
由于您已经检查堆栈不为空,您可以安全地强制解包
while !stack.isEmpty
let current = stack.popLast()!
switch current
// ...
请改用removeLast()
。此方法预计数组不为空,并返回一个(非可选的)数组元素:
while !stack.isEmpty
let current = stack.removeLast()
switch current
// ...
在 while 条件中使用 popLast()
和可选绑定:
while let current = stack.popLast()
switch current
// ...
【讨论】:
以上是关于switch 在递归类型中必须是详尽的的主要内容,如果未能解决你的问题,请参考以下文章