Smalltalk:上下文无法返回

时间:2014-03-31 21:29:12

标签: closures block smalltalk

以下Smalltalk代码返回错误"上下文无法返回"如果我一个接一个地执行它们。有人有解释吗?

  f := [ :x :y | ^x + y].
  sum:= f value: 3 value: 6.

如果我一次执行它们,它会起作用并按预期返回9

1 个答案:

答案 0 :(得分:8)

你可能想写

f := [ :x :y | x + y].
sum:=f value: 3 value: 6.

为什么?

让我告诉你一下

非本地回报。

如果要从方法中返回某些内容,可以在方法中使用^插入符来执行此操作:

doSomethingUseful
    ^ self calculate + 1

这是正常的回报。一切还好。现在输入块。

总是隐式地从块中返回一些东西,即它的最后一个表达式的值。 因此,执行时,此块将返回42

[1 + someObject invert.
 anotherObject * 4.
 42].

您可以在方法中使用它:

doSomethingUseful: someObject to: anotherObject
    | myValue |
    myValue := [1 + someObject invert.
                anotherObject * 4.
                42] value.
    ^ self calculate + myValue

但是,有时您必须从函数中退出。 一个典型的例子是 guard子句,如下所示:

doThis
    self someValueSatisfied ifFalse: [^ self]
    self calculate.
    ^ self someValueComputed.

如果#someValueSatsified返回false,则该方法会立即返回,并且永远不会执行#calculate#someValueComputed。此效果称为非本地返回,因为您从块而不是返回到其调用上下文(这将是本地),但形成了它定义的方法(! )。

为什么一气呵成?

这是由于处理“Do-it”的方式,例如。吱吱声或Pharo。当您按下Ctrl-D(或等效的)时,当前选择的代码被秘密编译为一种方法(好吧,发生了一点点,但让我们忽略它)。如果执行1 halt并查看调试器,则可以看到。

因此,按行执行代码将执行以下操作:

DoIt
    f := [ :x :y |    ^(x+y). ]. "! f is now defined in the work space"

DoIt
    sum:=f value: 3 value: 6.

首先,创建块并将其存储在工作区中的某个位置f。然后这个do-it退出,下一个执行。 Smalltalk在您的工作区中找到f,即存储的块。它试图执行它并遇到非本地返回。但是,非本地返回仅从定义函数返回,该函数不再执行,因此我们无法从中返回。

当您一次性执行所有操作时,这将是:

DoIt
    f := [ :x :y |    ^(x+y). ].
    sum:=f value: 3 value: 6.

与上面的几乎相同,除了现在执行f时,非本地返回可以工作,因为我们仍然在函数中定义了块。所以我们可以从中回来。在这种情况下,非本地返回工作。