SYZ*_*333 2 loops smalltalk break while-loop gnu-smalltalk
whileTrue
在不需要返回的 GNU Smalltalk 循环中,有什么简单而简洁的方法可以中断?
这是我的代码。如果char_stack
为空,我想在第 31 行结束时中断循环。
https://gist.github.com/SYZYGY-DEV333/ea3f5eeb3473927c8faa294bb72a8858
任何帮助将非常感激。
通常,除了从封闭方法返回外,Smalltalk 没有办法从循环中中断。
尝试将您的循环提取到另一种方法中,您可以从中返回以中断循环。
在某种程度上,Smalltalk 语言甚至没有循环……但有些方法碰巧不止一次评估块。因此它没有终止“循环”的特殊方法。回归才是正道。
如果您还没有这样做,请熟悉 Collection 的不同迭代方法:do:
, select:
, collect:
, detect:ifNone:
, ... 后者是在集合上运行“不完整”循环的另一种方法,但它不能解决所有情况您可能希望“休息一下”。
Peter Deutsch撰写的 Byte 杂志(1982 年)中一篇名为Building Control Structures in the Smalltalk-80 System 的文章展示了为循环内可能发生的不常见事件实现 while 循环中断是多么容易。
为了实现这一点,我们只需要一个新类和一个扩展BlockClosure
,总共9 行代码(!)。
类: BlockWithExit
,Object
具有两个 ivars的子类exit
以及block
以下方法
on: aBlock
block := aBlock
value
exit := [^nil].
^block value
exit
exit value
Run Code Online (Sandbox Code Playgroud)
扩大
BlockClosure>>withExit
^BlockWithExit new on: self
Run Code Online (Sandbox Code Playgroud)
就是这样!
例子
查找集合的最大值,直到耗尽或nil
找到为止(罕见事件)
maxBeforeNil: aCollection
| max supplier loop |
max := 0.
supplier := aCollection readStream.
loop := [
[supplier atEnd]
whileFalse: [
value := supplier next.
value isNil ifTrue: [loop exit].
max := max max: value]] withExit.
loop value.
^max
Run Code Online (Sandbox Code Playgroud)
为什么会这样?因为具有非本地返回的块从定义该块的方法中退出。
在本例中,该方法是BlockWithExit>>value
,因此当[^nil]
从 进行计算时loop exit
,流将value
在 之后退出并转到其发送者loop value
。
Deutsch 的发现的突出推论是,可以使用在 ivar 中定义退出块的相同技巧来构建整个机制, 例如: 。Exceptions
exit := [^nil]