exi*_*all 5 recursion enums infinite-loop recursive-datastructures swift
我enum在 Swift 中创建了一个递归函数,编译时没有错误或警告,但当我尝试实例化它时,它会进入无限循环:
enum Tree<T> {
case Leaf(T)
case Branch(T, [Tree<T>])
}
Tree.Leaf(0) // enters infinite loop
Tree.Branch(0, []) // enters infinite loop
Run Code Online (Sandbox Code Playgroud)
无限循环发生在实例化时,而不是在打印或任何其他使用实例时发生。即使对结果没有做任何事情,Tree.Leaf(0)仍然会永远运行。需要明确的是:无限循环发生在运行时,而不是编译时,而是在实例化时立即发生。
奇怪的是,以下非常相似的数据结构可以完美地工作:
enum WorkingTree<T> {
case Leaf(T)
case Branch([WorkingTree<T>]) // notice the lack of a `T` in this case
}
WorkingTree.Leaf(0) // works fine
WorkingTree.Branch([.Leaf(1), .Leaf(2)]) // works fine
Run Code Online (Sandbox Code Playgroud)
也许更奇怪的是,以下数据结构也可以完美运行:
enum ConcreteTree {
case Leaf(Int)
case Branch(Int, [ConcreteTree])
}
ConcreteTree.Leaf(0) // works fine
ConcreteTree.Branch(0, []) // works fine
Run Code Online (Sandbox Code Playgroud)
为什么当我尝试实例化它时,我的原始数据结构进入无限循环,而其他几乎相同的数据结构却没有?
编辑:
在 Swift REPL 中,问题似乎取决于实例化是否发生在与类型声明相同的“块”中。如果我在 Swift REPL 中输入以下内容:
1> enum Tree<T> {
2. case Leaf(T)
3. case Branch(T, [Tree<T>])
4. } // press enter, declare type
5> Tree.Leaf(0) // separate command to the REPL
Run Code Online (Sandbox Code Playgroud)
然后它会因无限循环而失败。但是,如果我将它们作为同一语句的一部分输入:
1> enum Tree<T> {
2. case Leaf(T)
3. case Branch(T, [Tree<T>])
4. } // press down arrow, continue multiline command
5. Tree.Leaf(0) // part of the same command
Run Code Online (Sandbox Code Playgroud)
然后它不会进入无限循环,并按预期工作。
可能发生什么事?
编辑2:
事情变得更加奇怪了。以下代码编译并运行,但在一个非常意外的点进入无限循环:
enum Tree<T> {
case Leaf(T)
case Branch(T, [Tree<T>])
}
let test = Tree.Leaf(0)
print("Milestone 1") // prints
switch test {
case .Leaf(_): print("Milestone 2") // prints
default: print("This should never be called")
}
func no_op<T>(x: T) {}
no_op(test) // infinite loop entered here
print("Milestone 3") // DOES NOT print
no_op(Tree.Leaf(0))
print("Milestone 4") // DOES NOT print
Run Code Online (Sandbox Code Playgroud)
什么可能将无限循环推迟到该no_op调用之前?
你忘了说indirect:
enum Tree<T> {
indirect case Leaf(T)
indirect case Branch(T, [Tree<T>])
}
Run Code Online (Sandbox Code Playgroud)
我对代码在没有它的情况下编译感到有点惊讶;我建议提交错误报告。