GNU Smalltalk - 在没有 return 的情况下从 whileTrue 循环中断

GNU Smalltalk - Break from whileTrue loop without return

在 GNU Smalltalk 中从不需要返回的 whileTrue 循环中断的简单明了的方法是什么?

这是我的代码。如果 char_stack 为空,我想在最后的第 31 行中断循环。

https://gist.github.com/SYZYGY-DEV333/ea3f5eeb3473927c8faa294bb72a8858

如有任何帮助,我们将不胜感激。

一般来说,Smalltalk 没有办法从循环中中断,除了 return 从封闭方法中断。

尝试将循环提取到另一个方法中,您可以从中return 中断循环。

在某种程度上,Smalltalk 语言甚至没有循环......但有些方法碰巧不止一次地评估块。因此它没有特殊的方式来终止 "loops"。 Return 就是这样。

如果您还没有这样做,请熟悉 Collection 的不同迭代方法:do:select:collect:detect:ifNone:、...后者是 运行 对集合进行 "incomplete" 循环的另一种方法,但它并不能解决您可能希望 "break".

的所有情况

其中一篇 articles of the Byte magazine (1982) 在 Smalltalk-80 系统中构建控制结构 Peter Deutsch,显示了为循环内可能发生的 偶发事件 实施 while 循环中断是多么容易。

要实现这一点,我们只需要一个新的 class 和对 BlockClosure 的扩展,总共 9 行代码 (!)。

classBlockWithExitObject 的子class 有两个 ivars exitblock 和以下方法

on: aBlock
  block := aBlock

value
  exit := [^nil].
  ^block value

exit
  exit value

分机

BlockClosure>>withExit
  ^BlockWithExit new on: self

就是这样!

例子

找到集合的最大值,直到用尽或找到 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

为什么这样工作?因为一个非局部的块return从定义该块的方法中退出.

在这种情况下,此方法是 BlockWithExit>>value,因此当从 loop exit 评估 [^nil] 时,流程退出 value 并转到其发送者,紧接着 loop value.

Deutsch 发现的突出推论是 Exceptions 的整个机制都可以使用同样的技巧构建 在 ivar 中定义一个退出块,例如:exit := [^nil].