Swift中的递归枚举

时间:2015-09-26 17:26:22

标签: swift enums swift2 func

我正在学习Swift 2(和C,但也不是很长时间),并且我已经达到了一个让我在递归枚举方面付出很多努力的地步。

如果它是递归的,我似乎需要在indirect之前放置enum。然后我有第一个在括号之间有Int的情况,因为在交换机后面它会返回Integer,是吗?

现在出现了第二个案例Addition的第一个问题。在那里,我必须在括号之间放置ArithmeticExpression。我尝试将Int放在那里,但它给了我一个错误,必须是ArithmeticExpression而不是Int。我的问题是为什么?我无法想象这是什么。为什么我不能在那里放两个Int

下一个问题是关于ArithmeticExpression。在func solution中,它包含一个名为expression的值ArithmeticExpression,这是正确的吗?其余的至少目前是完全清楚的。如果有人能够以一种简单的方式向我解释,那就太好了。

以下是完整代码:

indirect enum ArithmeticExpression {
    case Number(Int)
    case Addition(ArithmeticExpression, ArithmeticExpression)
}

func solution(expression: ArithmeticExpression) -> Int {
    switch expression {
    case .Number(let value1):
        return value1;
    case . Addition(let value1, let value2):
        return solution(value1)+solution(value2);
    }
}

var ten = ArithmeticExpression.Number(10);
var twenty = ArithmeticExpression.Number(20);
var sum = ArithmeticExpression.Addition(ten, twenty);
var endSolution = solution(sum);
print(endSolution);

2 个答案:

答案 0 :(得分:2)

Addition案例需要两个ArithmeticExpression而不是两个Int的原因是它可以处理这样的递归情况:

ArithmeticExpression.Addition(ArithmeticExpression.Addition(ArithmeticExpression.Number(1), ArithmeticExpression.Number(2)), ArithmeticExpression.Number(3))

或者,不止一行:

let addition1 = ArithmeticExpression.Addition(ArithmeticExpression.Number(1), ArithmeticExpression.Number(2))
let addition2 = ArithmeticExpression.Addition(addition1, ArithmeticExpression.Number(3))

代表:

(1 + 2) + 3

递归定义允许您不仅添加数字,还允许添加其他算术表达式。这就是enum的力量所在:它可以表达多个嵌套的加法运算。

答案 1 :(得分:0)

PeterPan,有时我认为过于逼真的示例比帮助多得多,因为在试图理解示例代码时很容易陷入困境。

递归枚举只是具有关联值的枚举,这些关联值是枚举自身类型的情况。而已。只是具有可设置为与该枚举相同类型的关联值的个案的枚举。 #endof

为什么这是个问题?为什么用关键词“间接”代替“递归”呢?为什么根本不需要任何关键字?

枚举被“假定”按值复制,这​​意味着它们应具有与案例相关的值,这些值具有可预测的大小-由基本类型(如Integer等)组成的案例组成。然后,编译器可以通过实例化原始枚举值或关联值的类型来猜测常规枚举的最大可能大小。毕竟,您只选择了一种情况就获得了一个枚举-因此,无论哪种情况下关联值类型的最大选择,这都是初始化时枚举类型可以得到的最大大小。然后,编译器可以在堆栈上预留一定数量的内存,并且知道该枚举实例的任何初始化或重新分配都不能大于此值。如果用户将枚举设置为关联值较小的大小写,也可以,并且如果用户将枚举设置为关联值类型最大的大小写。

但是,一旦您定义了一个枚举,该枚举混合了大小不同的关联类型的个案,其中包括也属于相同类型的枚举的值(因此它们本身可以用任何枚举个案初始化),则变得不可能猜测枚举实例的最大大小。用户可以继续使用允许与枚举类型相同的关联值的用例进行初始化-本身也用同样类型的用例进行初始化,依此类推:无休止的递归或可能性树。指向枚举的枚举的递归将继续进行,直到用不指向另一个枚举的“简单”类型的关联值初始化枚举为止。考虑一个简单的Integer类型,它将“终止”枚举链。

因此,编译器无法为这种枚举类型在堆栈上预留正确大小的内存块。而是将与大小写关联的值作为POINTERS对待存储关联值的堆内存。该枚举本身可以指向另一个枚举,依此类推。这就是为什么关键字是“间接”的原因-关联值是通过指针间接引用的,而不是直接由值引用的。

这类似于将inout参数传递给函数-代替编译器将值复制到函数中,它传递指针以引用堆内存中的原始对象。

这就是全部。不能轻易猜出其最大大小的枚举,因为它可以用相同类型的枚举和长度不确定的链中不可预测的大小初始化。

如各种示例所示,此类枚举的典型用法是您要构建值树,例如在括号内嵌套计算的公式的公式树,或在一个枚举中捕获的带有节点和分支的祖先树。初始化。编译器通过使用指针来引用枚举的关联值而不是堆栈上固定的内存块来解决所有这些问题。

所以基本上-如果您能想到代码中想要让枚举链相互指向并为关联值提供各种选项的情况-那么您将使用并理解递归枚举!