请考虑以下消息序列:
1. s := '' writeStream.
2. s nextPutAll: '123'.
3. s skip: -3.
4. s position "=> 0".
5. s size "=> 3".
6. s isEmpty "=> false".
7. s contents isEmpty "=> true (!)"
6 和 7 不是矛盾的,或者至少是令人困惑的吗?这种行为背后的逻辑是什么?(海豚也有类似的功能。
更新
正如@MartinW观察到的那样(见下面的评论),ReadStream
和ReadWriteStream
的行为不同(我们可以说,正如预期的那样)。
从实际的角度来看,我更担心的兼容性是FileStream
的兼容性,其中contents
消息不限于当前position.
这种差异使原本很好的"定律"无效,根据该定律,任何使用内存流(字符串或字节数组)的代码也适用于文件流,反之亦然。这种等效性对于测试和教学原因非常有用。通过将方法#truncate
添加到WriteStream
中,可以轻松恢复明显的功能损失,这将明确缩短当前position
的size
[参见下面与Derek Williams的讨论]
在许多Smalltalks(如VAST)中,方法注释很好地解释了它:
WriteStream>>contents
"Answer a Collection which is a copy collection that the receiver is
streaming over, truncated to the current position reference."
PositionableStream>>isEmpty
"Answer a Boolean which is true if the receiver can access any
objects and false otherwise."
注意"截断到当前位置参照"。
在您的示例中,contents
是一个空字符串,因为您使用 skip: -3
将位置设置回 0
这种行为不仅正确,而且非常有用。 例如,考虑从集合生成逗号分隔列表的方法:
commaSeparatedListFor: aCollection
ws := '' writeStream.
aCollection do: [ :ea |
ws print: ea; nextPutAll: ', ' ].
ws isEmpty
ifFalse: [ ws position: ws position - 2 ].
^ws contents
在这种情况下,该方法可能已经写入了最后的尾随 ", ",但我们希望contents
排除它。