2

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

这是我的代码。char_stack如果为空,我想在第 31 行结束循环。

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

任何帮助将非常感激。

4

2 回答 2

5

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

尝试将您的循环提取到另一种方法中,您可以从中返回以从循环中中断。

在某种程度上,Smalltalk 语言甚至没有循环......但有些方法碰巧不止一次地评估块。因此,它没有终止“循环”的特殊方法。回归是一种方式。

如果您还没有这样做,请熟悉一下 Collection 的不同迭代方法:do:, select:, collect:, detect:ifNone:, ... 后者是在集合上运行“不完整”循环的另一种方法,但它不能解决所有情况您可能希望“休息”。

于 2018-10-07T08:56:22.240 回答
5

Peter Deutsch在 Byte 杂志(1982) 上发表的一篇题​​为“在 Smalltalk-80 系统中构建控制结构”的文章展示了为循环内可能发生的不常见事件实现 while 循环中断是多么容易。

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

具有两个 ivars和以下方法的类: BlockWithExit,子类Objectexitblock

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

为什么它会这样工作?因为具有非本地返回的块从定义该块的方法中退出

在这种情况下,此方法是BlockWithExit>>value,因此当[^nil]从 评估时loop exit,流退出value并转到它的发送者,就在 之后loop value

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

于 2018-10-08T12:21:09.410 回答