解释一段Smalltalk代码?

时间:2011-01-30 03:03:36

标签: smalltalk

我无法理解这段Smalltalk代码:

[(line := self upTo: Character cr) size = 0] whileTrue.

有人可以帮忙解释一下吗?

4 个答案:

答案 0 :(得分:12)

一件简单的事情,如果您有代码来自的图像,则在其上运行调试器并逐步完成。

如果您遇到了脱离上下文的代码,例如邮件列表帖子,那么您可以浏览其中一条消息的实施者并查看其功能。例如,#size和#whileTrue非常标准,所以我们暂时不会跳过这些,但#upTo:听起来很有趣。它让我想起了流方法,并在它上面启动了实现者,证实了(在Pharo 1.1.1中),ReadStream定义了它。没有方法注释,但OmniBrowser在方法名称旁边显示一个小箭头,表示它是在超类中定义的。如果我们检查直接超类,PositionableStream,有一个很好的方法注释,解释该方法的作用,它是从流中抽取,直到到达参数指定的对象。

现在,如果我们逻辑地解析代码,它似乎是:

  • 从流中读取一行(即最多为cr)
    • 如果它为空(size = 0),则循环继续
    • 如果不是,则返回

因此,代码会跳过所有空行并返回第一个非空行。为了确认,我们可以在多行字符串上传递一个流并像这样运行它:

line := nil.
paragraph := '


this is a line of text.
this is another line
line number three' readStream.
[(line := paragraph upTo: Character cr) size = 0] whileTrue.
line. "Returns 'this is a line of text.'"

答案 1 :(得分:1)

这是否更具可读性:

while(!strlen(line=gets(self)))

如果feof或任何其他错误,则上面的表达式有一个缺陷,line == NULL
Smalltalk表达式也是如此,如果遇到流结束,upTo:将回答一个空集合,并且你将有一个无限循环,除非你有一个特殊的流在流结束时引发错误...试试

String new readStream upTo: Character cr

答案 2 :(得分:1)

Smalltalk的优先规则是
第一:一元信息
第二:二进制消息
第三:关键字消息
最后:从左到右

这个从左到右的顺序可以通过使用括号即()括号来改变。首先评估括号对内的表达式。 在括号嵌套的情况下,首先评估最内侧括号,然后向外朝向外括号,最后是括号外的表达式的剩余部分。

由于从左到右的强烈倾向,我经常发现从右到左阅读表达式很有用。

所以[(line := self upTo: Character cr) size = 0] whileTrue.

从头到尾接近它给我们以下解释。

.结束表达式。相当于C或Java中的;

whileTrue左边是什么? ]关闭一个块对象。

因此whileTrue是发送到块[的一元消息... ] 即继续执行此块,而块评估为真

一个块返回块中评估的最后一个表达式的结果。

块中的最后一个表达式是size = 0比较。和二进制消息。

size通常是发送给接收方的一元消息。我们正在查看某些内容的size,看看它是否为0。如果某个内容的size0,请继续。

我们检查size是什么?紧接着消息名称左侧的表达式。 size左侧是
(line := self upTo: Character cr)

这就是我们想知道的大小。

所以,是时候把这个表达放在刀下了。

(line := self upTo: Character cr)是一项任务。 line将得到结果 分配给self upTo: Character cr

那个表达的右边是什么? cr这是一个一元信息,因此具有最高优先级。它被发送到什么地方。即cr消息的接收者是什么?

左边是Character。因此,向Character类发送消息cr这将计算为具有值13的类Character的实例 - 即回车符。

所以现在我们已经到了self upTo: aCarriageReturn

如果self - 收到self upTo: aCarriageReturn消息的对象 - 不理解消息名称sizeUpto:,则会引发异常。

因此,如果这是来自工作系统的代码,我们可以推断出self必须是一个理解sizeUpTo:的对象。此时,我经常试图搜索按摩名称以查看哪些类在其知道和理解的消息名称列表中具有名为sizeUpto:的消息(即其消息 protocol )。

(在这种情况下,它对我没有好处 - 它不是我的Smalltalk系统中任何类的方法。)

但似乎要求self处理包含(可能)许多回车的字符串。

所以,返回aCharacterString的第一部分,直到第一次回车。

如果从开始到第一次回车的aCharacterString的长度为零,继续前进并再次完成。

所以似乎我们正在处理多个以cr结尾的字符串的串联,并依次处理每个字符串,直到找到一个不为空的字符串(除了它的回车符),然后将它分配给{{ 1}}

答案 3 :(得分:-2)

我个人不喜欢Smalltalk的一件事是,虽然消息传递一直用于做几乎所有事情,但有时很难确定哪些消息被发送到哪个接收器。这是因为Smalltalk没有围绕消息发送的任何分隔符(例如Objective-C),而是允许您在遵循一组优先级规则时链接消息发送,这些规则类似于“从左到右解释消息发送” ,除非用括号分隔,否则首先评估包含许多关键字的消息,然后评估二进制关键字消息,然后是一元,然后不再使用关键字消息。“当然,使用临时变量甚至只是括号使消息的顺序显式化可以减少您必须考虑此操作顺序的情况的数量。下面是上面代码的示例,分为多行,使用临时变量和括号进行显式消息排序以提高可读性。我认为关于代码的意图有点清楚:

line = (self upTo: (Character cr)).

([((line size) = 0)] whileTrue).

基本上,line是连接字符串self中的字符直到回车符(Character cr)时创建的字符串。 然后,我们检查行的字符大小,并检查它是否等于0,并且因为我们将它放在一个块(括号)中,我们可以发送一个whileTrue,它重新计算块中的条件,直到它返回true。所以,是的,而如果它被称为doWhileTrue或类似的东西,真的会更清楚。

希望有所帮助。