result := String new.
1 to: 10 do: [:n | result := result, n printString, ’ ’].
smalltalk中的所有内容都是一个对象,并且这些对象通过 消息。
我不明白上面的代码如何理解to:do的消息:
如何将块从1迭代到10? 它怎么知道必须重复多次该块?
有人可以解释幕后发生的事情吗?
答案 0 :(得分:7)
所有Smalltalk消息均遵循模式<receiver> <message>.
。在这种情况下,接收者为1
(Number
的子实例),消息为to:do:
。
您可以浏览类Number
并在那里查看to:do:
的实现:
to: stop do: aBlock
| nextValue |
nextValue := self.
[nextValue <= stop]
whileTrue:
[aBlock value: nextValue.
nextValue := nextValue + 1]
在您的示例中,stop
是10
,而aBlock
是[:n | result := result, n printString, ’ ’]
。因此的确,它是在向value:
重复发送aBlock
。
现在,除此之外,许多Smalltalks在看到for:to:
消息时都会生成特殊的字节码,但这只是一种优化。
答案 1 :(得分:1)
考虑方法
m
1 to: 10 do: [:i | self doSomethingWith: i]
这是Pharo生成的字节码
pushConstant: 1 ; i := 1
popIntoTemp: 0 ;
@2: pushTemp: 0 ; i <= 10 ?
pushConstant: 10 ;
send #'<=' ;
jumpFalse: @1 ; if false, go to end
self ; self doSomethingWith: i
pushTemp: 0 ;
send #doSomethingWith: ;
pop ;
pushTemp: 0 ; i := i + 1
pushConstant: 1 ;
send #'+' ;
popIntoTemp: 0 ;
jumpTo: @2 ; loop
@1: returnSelf
如您所见,#to:do
从未发送,而#'<='
和#+
则一直发送(即使它们不在源代码中!)。为什么?由于Bert在回答中所说:这些消息是由Smalltalk编译器优化的。对于Pharo,优化发生在#to:do:
中。在其他方言中,#to:do:
是根据#whileTrue:
来实现的,#to:do:
是经过优化的一种。
一旦您了解了它的工作原理 ,请回想起来,好像1
是带有接收者10
和参数{{1 }}和块[:i | self doSomethingWith: i]
。优化不应掩盖您的思维必须遵循的语义。