为什么此代码将变量a设置为9?

gaa*_*kam 2 variables loops smalltalk parity

我对这段代码感到困惑:

| a b c| a := 1. b := [a := a + 1]. c := [a := a - 2. b].
        10 timesRepeat: (a even ifTrue: b ifFalse: c). a
Run Code Online (Sandbox Code Playgroud)

我的假设是这段代码将设置a-19。每次迭代将测试,如果a是偶数,但a会是奇数所以c会被调用,从其减去2a而不影响其校验。c不会调用,b因为如果我对块的理解正确,那么将返回块的最后一个元素,而不是求值;所以c会返回b,但timesRepeat无论是无论如何返回丢弃所以这bc没有任何效果。

我的假设被证明是错误的:这一段代码集a9代替。为了查看发生了什么,我对这段代码进行了一些修改:

| a b c| a := 1. b := [Transcript show: (a displayString). a := a + 1]. c := [Transcript  show: (a displayString). a := a - 2. b.].
           10 timesRepeat: (a even ifTrue: b ifFalse: c). a
Run Code Online (Sandbox Code Playgroud)

这是打印出来的内容:

1-1012345678
Run Code Online (Sandbox Code Playgroud)

如此看来毕竟b 称为?我的假设是错误的,b它返回而不是调用吗?

让我们尝试检查一下:

jkl := [Transcript show: 'I am called too.'].
asdf := [Transcript show: 'I am called!'. jkl].

10 timesRepeat: asdf
Run Code Online (Sandbox Code Playgroud)

不,这里asdf不打jkl

I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!
Run Code Online (Sandbox Code Playgroud)

不管怎样,如果c总是只调用b,其效果将是有效的。减去1a; 但这不会发生。取而代之的是,第一次迭代似乎在调用c,然后,神秘地,每次迭代似乎都在调用b,即使a是奇怪的!

这里发生了什么??

lur*_*ker 9

所述timesRepeat:选择器想要一个块作为一个参数。您使用括号内的表达式来调用它:

10 timesRepeat: (a even ifTrue: b ifFalse: c).
Run Code Online (Sandbox Code Playgroud)

但是,恰好发生这种情况,它c被定义为[a := a - 2. b]返回值的块,b并且恰好是一个块。所以timesRepeat:很高兴,并且它b在每次迭代中a都执行奇数的块。如果正确编写为:

10 timesRepeat: [a even ifTrue: b ifFalse: c].
Run Code Online (Sandbox Code Playgroud)

然后最后,a将是预期的-19。

关于您的陈述:如果我对块的理解是正确的,那么将返回块的最后一个元素,而不是评估结果,实际上不是这种情况。对块中的最后一条语句没有特殊处理,除了它的结果确实在执行该块时作为该块的值返回之外。您在块中的最后一条语句只是变量的名称。变量的值恰好是一个块,但无论它是什么,只要在Smalltalk中仅具有一个变量名作为语句就可以返回该变量的值。如果变量恰好是一个块,则可以得到该块。该块不执行。

考虑以下块:

[a := 1. b := 2. c := a+b]
Run Code Online (Sandbox Code Playgroud)

执行此块时,a它将具有值1,b值2和c值3。该块将返回的值是的值c,即3。

[a := 1. b := 2. a]
Run Code Online (Sandbox Code Playgroud)

如果执行此块,结果将是的值a,即1。

[a := 1. b := 2. c := [a+b]. c]
Run Code Online (Sandbox Code Playgroud)

如果执行此块,则结果将是变量c代表的块。它不执行块c。这与先前的示例一致。

所以,当你执行块[Transcript show: 'I am called!'. jkl].,将jkl在年底不执行。它的值刚刚返回。如果要执行它,则可以编写asdf := [Transcript show: 'I am called!'. jkl value].一个A块,该块将在发送value消息时执行。执行块[Transcript show: 'I am called!'. jkl value].的结果将是执行块的结果jkl