解释一段Smalltalk代码?

问题描述:

我无法理解这片的Smalltalk代码:解释一段Smalltalk代码?

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

任何人可以帮助解释一下吗?

一个简单的事情就是,如果你有代码来自的图像,那么在它上面运行一个调试器并逐步完成。

如果您发现代码与上下文无关,就像邮件列表文章一样,那么您可以浏览其中一条消息的实现者并查看其功能。例如,#size和#whileTrue是非常标准的,所以我们暂时略过,但#upTo:听起来很有趣。它让我想起了流式方法,并提出了实现方法,证实了(在Pharo 1.1.1中),ReadStream定义了它。没有方法注释,但OmniBrowser在方法名称旁边显示一个小箭头,指示它在超类中定义。如果我们检查直接的超类,定位流,有一个很好的方法注释来解释这个方法做了什么,它是从流中绘制直到到达由参数指定的对象。

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

  • 读取来自流的线(即,高达一CR)
    • 如果它是空的(大小= 0) ,循环将继续
    • 如果不是,则返回

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

约Smalltalk的
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.'" 
+0

感谢朋友,你的回答帮助我很多:)顺便说一句,我认为在调试器中修复代码是一项非常有用的技能。案例一些方法不是很容易调试,除了方法从字符串类别继承,rigth? – parsifal 2011-01-30 06:20:33

+0

不客气!我不确定你的其他问题是什么,你可以用不同的方式说出来吗? – 2011-01-30 07:40:22

有一件事,我个人不是一个巨大的风扇的是,虽然消息传递使用一贯地做几乎所有的事情,有时候很难确定什么消息被发送到什么接收器。这是因为Smalltalk没有围绕消息发送(例如Objective-C)的任何分隔符,而是允许您链接消息发送,同时遵循一组优先规则,这些优先规则类似于“从左向右解释消息发送,除非用圆括号分隔,否则首先会评估包含多个关键字的消息,然后评估二进制关键字消息,然后进行一元化处理,然后再进行一次关键字处理。“当然,使用临时变量或者只是括号来明确消息的顺序可以减少你必须考虑这个操作顺序的情况的数量。下面是上面代码的一个例子,分成多行,使用临时变量和括号来显式消息排序以提高可读性。我认为这是对代码的意图更清楚一点:

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

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

所以基本上,行是当你在字符串自我串连字符直到回车字符(字符CR)创建的字符串。 然后,我们用字符检查行的大小,并检查它是否等于0,并且因为我们把它放在一个块(方括号)中,我们可以发送一个whileTrue,它重新评估块中的条件,直到它返回true 。所以,是的,虽然真的会更清楚,如果它被称为doWhileTrue或类似的东西。

希望有所帮助。

这是更具可读性:

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

上述表达式有一个缺陷,如果FEOF或任何其他错误,行== NULL
所以有Smalltalk的表达,如果遇到流的末尾,高达:将回答一个空的集合,你就会有一个无限循环,除非你有一个提高对流的末尾错误特殊的流...尝试

String new readStream upTo: Character cr 

Smalltalk中的优先级规则
第一:一元的消息
第二:二进制消息
第三:关键字消息
最后:左至右

的左到右此顺序,可以通过使用括号即()括号来改变。首先评估一对括号内的表达式。 在括号嵌套的地方,首先计算最内侧的括号,然后向外朝向外括号,最后是括号外的表达式剩余部分。

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

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

从最终回到开始走近它为我们提供了如下解释。

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

whileTrue它的左边是什么? ]关闭块对象。

所以whileTrue被发送到块[一元的消息...... ] 即继续这样做块,而该块计算为true

块返回块计算的最后一个表达式的结果。

该块的最后一个表达式是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:在他们知道和理解的消息名称列表中(即他们的消息协议)。

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

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

因此,返回aCharacterString的第一部分,直到第一个回车。

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

所以它似乎是我们正在处理多个cr终止字符串的串联,并依次处理每个字符串,直到我们发现一个不是空的(除了它的回车),并将其分配给line