Ruby 的 throw-catch 是如何实现的?
How is Ruby's throw-catch implemented?
在 ruby 中,您可以 throw :label
只要您将所有内容都包装在 catch(:label) do
块中。
我想将它添加到自定义的 lispy 语言中,但我不确定它是如何在后台实现的。有什么指点吗?
这是一个非本地出口的例子。如果您使用宿主语言(在本例中为 C)的调用堆栈进行目标语言的函数调用(例如,lisp 中的函数调用等同于 C 中的函数调用),那么最简单的方法是使用宿主语言的非本地出口形式。在 C 中,这意味着 setjmp/longjmp.
但是,如果您要单独维护目标语言的调用堆栈,那么您有多种选择来执行此操作。一种非常简单的方法是让每个词法作用域出口产生两个值;返回的实际值和异常状态(如果有)。然后您可以在运行时检查异常并将该值向上传播。这有一个缺点,即当没有发出条件信号时,函数调用会产生额外的成本,但对于玩具语言来说可能就足够了。
本书 "Lisp In Small Pieces" 介绍了大约六种处理方法,如果您有兴趣的话。
在 ruby 中,您可以 throw :label
只要您将所有内容都包装在 catch(:label) do
块中。
我想将它添加到自定义的 lispy 语言中,但我不确定它是如何在后台实现的。有什么指点吗?
这是一个非本地出口的例子。如果您使用宿主语言(在本例中为 C)的调用堆栈进行目标语言的函数调用(例如,lisp 中的函数调用等同于 C 中的函数调用),那么最简单的方法是使用宿主语言的非本地出口形式。在 C 中,这意味着 setjmp/longjmp.
但是,如果您要单独维护目标语言的调用堆栈,那么您有多种选择来执行此操作。一种非常简单的方法是让每个词法作用域出口产生两个值;返回的实际值和异常状态(如果有)。然后您可以在运行时检查异常并将该值向上传播。这有一个缺点,即当没有发出条件信号时,函数调用会产生额外的成本,但对于玩具语言来说可能就足够了。
本书 "Lisp In Small Pieces" 介绍了大约六种处理方法,如果您有兴趣的话。