为什么此代码将变量 a 设置为 9?
Why does this code set the variable a to 9?
我被这段代码搞糊涂了:
| a b c| a := 1. b := [a := a + 1]. c := [a := a - 2. b].
10 timesRepeat: (a even ifTrue: b ifFalse: c). a
我的假设是这段代码会将 a
设置为 -19
。每次迭代都会测试 a
是否为偶数,但 a
是否为奇数,因此将调用 c
,从 a
中减去 2
而不影响其奇偶校验。 c
不会调用 b
因为,如果我对块的理解是正确的,块的最后一个元素是 returned 而不是求值;所以 c
会 return b
,但是 timesRepeat
会丢弃任何 returned 的东西所以 c
中的 b
没有效果.
我的假设被证明是错误的:这段代码将 a
设置为 9
。为了看看发生了什么,我稍微修改了这段代码:
| 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
这是打印的内容:
1-1012345678
所以看起来 b
是 调用的吗? b
是 returned 而不是调用是我的假设错误吗?
让我们尝试检查一下:
jkl := [Transcript show: 'I am called too.'].
asdf := [Transcript show: 'I am called!'. jkl].
10 timesRepeat: asdf
不,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!
而且无论如何,如果 c
总是调用 b
,它的效果将是有效地从 a
中减去 1
;但这不会发生。相反,第一次迭代似乎调用 c
然后,神秘地,每次迭代似乎调用 b
,即使 a
是奇数!
这是怎么回事??
timesRepeat:
选择器需要一个块作为参数。您使用括号内的表达式调用它:
10 timesRepeat: (a even ifTrue: b ifFalse: c).
不过,碰巧 c
被定义为块 [a := a - 2. b]
,其中 return 是 b
的值,而这恰好是一个块.所以 timesRepeat:
很高兴,它在 a
为奇数的每次迭代中执行块 b
。如果你正确地写成:
10 timesRepeat: [a even ifTrue: b ifFalse: c].
然后在最后,a
将是预期的 -19。
关于您的说法:如果我对块的理解是正确的,那么块的最后一个元素是 returned 而不是求值,这不是真正的案件。块中的最后一条语句没有特殊处理,除了它的结果确实 returned 作为块执行时的块值。块中的最后一条语句只是变量的名称。变量的值恰好是一个块,但不管它是什么,只要有一个变量名本身作为 Smalltalk 中的语句就可以 returns 变量的值。如果变量恰好是一个块,你就得到这个块。该块未执行。
考虑以下块:
[a := 1. b := 2. c := a+b]
执行此块时,a
的值为 1,b
的值为 2,c
的值为 3。该块的值将 return是c
的值,也就是3.
[a := 1. b := 2. a]
如果执行此块,结果将是 a
的值,即 1。
[a := 1. b := 2. c := [a+b]. c]
如果你执行这个块,结果将是变量c
代表的块。它不执行块 c
。这与前面的示例一致。
所以,当你执行块[Transcript show: 'I am called!'. jkl].
时,最后的jkl
不会被执行。它的价值只是 returned。如果你想执行它,你可以写 asdf := [Transcript show: 'I am called!'. jkl value].
发送 value
消息时将执行一个块。执行块 [Transcript show: 'I am called!'. jkl value].
的结果将是执行块 jkl
.
的结果
我可能是唯一一个,但我觉得下面第二句有点晦涩:
It just so happens, though, that c is defined as the block [a := a - 2. b] which returns the value of b and that happens to be a block. So timesRepeat: is happy, and it executes the block b on each iteration in which a is odd.
Smalltalk 的语义是:
- 评价接受者
- 评估参数
- 发送消息
顺序很重要,因为计算可能会产生副作用。
所以,实际发生的是:
- 接收者
10
的计算结果为 10
- 参数
a even ifTrue: b ifFalse: c
的计算结果为 b
。副作用 a = -1
.
- 消息
10 timesRepeat: b
或10 timesRepeat: [a := a + 1]
已发送
因此,a = 9
.
我被这段代码搞糊涂了:
| a b c| a := 1. b := [a := a + 1]. c := [a := a - 2. b].
10 timesRepeat: (a even ifTrue: b ifFalse: c). a
我的假设是这段代码会将 a
设置为 -19
。每次迭代都会测试 a
是否为偶数,但 a
是否为奇数,因此将调用 c
,从 a
中减去 2
而不影响其奇偶校验。 c
不会调用 b
因为,如果我对块的理解是正确的,块的最后一个元素是 returned 而不是求值;所以 c
会 return b
,但是 timesRepeat
会丢弃任何 returned 的东西所以 c
中的 b
没有效果.
我的假设被证明是错误的:这段代码将 a
设置为 9
。为了看看发生了什么,我稍微修改了这段代码:
| 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
这是打印的内容:
1-1012345678
所以看起来 b
是 调用的吗? b
是 returned 而不是调用是我的假设错误吗?
让我们尝试检查一下:
jkl := [Transcript show: 'I am called too.'].
asdf := [Transcript show: 'I am called!'. jkl].
10 timesRepeat: asdf
不,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!
而且无论如何,如果 c
总是调用 b
,它的效果将是有效地从 a
中减去 1
;但这不会发生。相反,第一次迭代似乎调用 c
然后,神秘地,每次迭代似乎调用 b
,即使 a
是奇数!
这是怎么回事??
timesRepeat:
选择器需要一个块作为参数。您使用括号内的表达式调用它:
10 timesRepeat: (a even ifTrue: b ifFalse: c).
不过,碰巧 c
被定义为块 [a := a - 2. b]
,其中 return 是 b
的值,而这恰好是一个块.所以 timesRepeat:
很高兴,它在 a
为奇数的每次迭代中执行块 b
。如果你正确地写成:
10 timesRepeat: [a even ifTrue: b ifFalse: c].
然后在最后,a
将是预期的 -19。
关于您的说法:如果我对块的理解是正确的,那么块的最后一个元素是 returned 而不是求值,这不是真正的案件。块中的最后一条语句没有特殊处理,除了它的结果确实 returned 作为块执行时的块值。块中的最后一条语句只是变量的名称。变量的值恰好是一个块,但不管它是什么,只要有一个变量名本身作为 Smalltalk 中的语句就可以 returns 变量的值。如果变量恰好是一个块,你就得到这个块。该块未执行。
考虑以下块:
[a := 1. b := 2. c := a+b]
执行此块时,a
的值为 1,b
的值为 2,c
的值为 3。该块的值将 return是c
的值,也就是3.
[a := 1. b := 2. a]
如果执行此块,结果将是 a
的值,即 1。
[a := 1. b := 2. c := [a+b]. c]
如果你执行这个块,结果将是变量c
代表的块。它不执行块 c
。这与前面的示例一致。
所以,当你执行块[Transcript show: 'I am called!'. jkl].
时,最后的jkl
不会被执行。它的价值只是 returned。如果你想执行它,你可以写 asdf := [Transcript show: 'I am called!'. jkl value].
发送 value
消息时将执行一个块。执行块 [Transcript show: 'I am called!'. jkl value].
的结果将是执行块 jkl
.
我可能是唯一一个,但我觉得下面第二句有点晦涩:
It just so happens, though, that c is defined as the block [a := a - 2. b] which returns the value of b and that happens to be a block. So timesRepeat: is happy, and it executes the block b on each iteration in which a is odd.
Smalltalk 的语义是:
- 评价接受者
- 评估参数
- 发送消息
顺序很重要,因为计算可能会产生副作用。
所以,实际发生的是:
- 接收者
10
的计算结果为10
- 参数
a even ifTrue: b ifFalse: c
的计算结果为b
。副作用a = -1
. - 消息
10 timesRepeat: b
或10 timesRepeat: [a := a + 1]
已发送
因此,a = 9
.