Swift中的递归枚举

Swift中的递归枚举,swift,enums,swift2,func,Swift,Enums,Swift2,Func,我学习Swift 2(和C,但也不是很长时间)的时间不长,我在递归枚举方面遇到了很多困难 如果是递归的,indirect似乎需要放在enum之前。然后我有第一个例子,括号之间有Int,因为后面在开关中它返回一个整数,对吗 现在,第二种情况下的第一个问题是添加。在这里,我必须把算术表达式放在括号之间。我试着把Int放在那里,但它给了我一个错误,它必须是算术表达式,而不是Int。我的问题是为什么?我无法想象这是怎么回事。为什么我不能在那里放两个Ints 下一个问题是关于算术表达式的。在func解决方

我学习Swift 2(和C,但也不是很长时间)的时间不长,我在递归枚举方面遇到了很多困难

如果是递归的,
indirect
似乎需要放在
enum
之前。然后我有第一个例子,括号之间有
Int
,因为后面在开关中它返回一个
整数,对吗

现在,第二种情况下的第一个问题是
添加
。在这里,我必须把
算术表达式
放在括号之间。我试着把
Int
放在那里,但它给了我一个错误,它必须是
算术表达式,而不是
Int
。我的问题是为什么?我无法想象这是怎么回事。为什么我不能在那里放两个
Int
s

下一个问题是关于算术表达式的。在
func
解决方案
中,它包含一个名为expression的值,其类型为
算术表达式
,是否正确?剩下的问题,至少目前是完全清楚的。如果有人能简单地向我解释,那就太好了

以下是完整的代码:

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);

加法
案例采用两个
算术表达式
s而不是两个
Int
s的原因是,它可以处理如下递归情况:

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

递归定义不仅允许添加数字,还允许添加其他算术表达式。这就是这个枚举的功能所在:它可以表达多个嵌套加法操作。

PeterPan,我有时认为太现实的示例会让人困惑,而不是帮助,因为很容易陷入理解示例代码的困境

递归枚举只是具有关联值的枚举,这些值是枚举自身类型的实例。就这样。只是一个枚举,其案例可以设置为与枚举相同类型的关联值#结束

为什么这是一个问题?为什么关键字“间接”而不是“递归”?为什么需要任何关键字呢

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

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

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

这类似于将inout参数传递给函数—编译器不会将值复制到函数中,而是传递一个指针来引用堆内存中的原始对象

这就是全部。无法轻易猜测其最大大小的枚举,因为它可以使用相同类型的枚举进行初始化,并且可以在长度不可预测的链中使用不可预测的大小

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

因此,基本上-如果您可以在代码中考虑这样一种情况,即希望枚举链彼此指向,并具有关联值的各种选项-那么您将使用并理解递归枚举