繁体   English   中英

Swift中的递归枚举

[英]Recursive Enumerations in Swift

我正在学习Swift 2(和C,但也不会很久),并且我已经达到了一个让我在递归枚举中挣扎很多的地方。

如果它是递归的,我似乎需要在enum之前放置indirect 然后我有第一个在括号之间有Int情况,因为稍后在switch中它返回一个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);

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的力量所在:它可以表达多个嵌套的加法运算。

PeterPan,我有时认为过于现实的例子比帮助更令人困惑,因为在试图理解示例代码时很容易陷入困境。

递归枚举只是一个枚举,其关联值是枚举自身类型的情况。 而已。 只是一个包含案例的枚举,可以设置为与枚举相同类型的关联值。 #结束

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

枚举被“假定”按值复制,这​​意味着它们应该具有可预测大小的大小写相关的值 - 由具有基本类型(如整数等)的大小写组成。 然后,编译器可以通过可以实例化的原始或关联值的类型来猜测常规枚举的最大可能大小。 毕竟你得到的枚举只有一个选择的案例 - 所以无论什么是案例中相关价值类型的最大选择,这是枚举类型在初始化时可以获得的最大尺寸。 然后,编译器可以在堆栈上留出大量内存,并且知道该枚举实例的任何初始化或重新分配永远不会大于该大小。 如果用户将枚举设置为具有小尺寸关联值的情况,则可以,并且如果用户将其设置为具有最大关联值类型的情况。

但是,只要您定义一个具有不同大小相关类型的案例混合的枚举,包括也是相同类型枚举的值(因此可以使用任何枚举案例进行初始化),就无法猜测枚举实例的最大大小。 用户可以使用允许与枚举相同类型的关联值的情况进行初始化 - 自身也使用同样类型的情况初始化,依此类推:无限递归或可能性树。 指向枚举的枚举的递归将继续,直到枚举初始化为具有“简单”类型的相关值而不指向另一个枚举。 想想一个简单的Integer类型,它将“终止”枚举链。

因此编译器无法为此类枚举在堆栈上留出正确大小的内存块。 相反,它将案例关联值作为POINTERS处理到存储关联值的堆内存。 这个枚举本身可以指向另一个枚举,依此类推。 这就是关键字是“间接”的原因 - 关联值是通过指针间接引用的,而不是直接通过值引用的。

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

所以这就是它的全部。 一个不容易达到其最大大小的枚举,因为它可以使用相同类型的枚举和不可预测长度的链中不可预测的大小进行初始化。

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

所以基本上 - 如果你能想到你的代码中你想让枚举链指向彼此的情况,以及相关值的各种选项 - 那么你将使用并理解一个递归枚举!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM