Smalltalk 在#注入:块中可见

Smalltalk 在#注入:块中可见,smalltalk,Smalltalk,此代码: ((1 to: 10) inject: (WriteStream on: String new) into: [ :strm :each | ((each rem: 3) = 0) ifTrue: [ strm nextPutAll: each printString; space;

此代码:

((1 to: 10)
    inject: (WriteStream on: String new)
    into: [ :strm :each |
        ((each rem: 3) = 0)
            ifTrue: [
                strm
                    nextPutAll: each printString;
                    space;
                    yourself ]]) contents
失败,因为在
ifTrue:
块中使用的
strm
未定义。为什么在那里看不见


编辑:我在VASt和Pharo中试用了它。

问题是隐含的
ifFalse:
分支返回
nil
。要解决此问题,请尝试以下操作:

((1 to: 10)
    inject: (WriteStream on: String new)
    into: [ :strm :each |
        ((each rem: 3) = 0)
            ifFalse: [strm]  "This is needed to avoid nil being returned"
            ifTrue: [
                strm
                    nextPutAll: each printString;
                    space;
                    yourself ]]) contents
根据方言(可用方法),您可以采用更短的方法

((1 to: 10) select: [ :each | (each rem: 3) = 0 ]) joinUsing: ' '
根据经验法则,任何
集合都可以:[:每个|东西如果真的:[]]
可以变成更直接、更可读的
集合选择:[]
集合拒绝:[]

这样做会将复杂性分散到几个独立的步骤(1.过滤,2.添加到流),而不是将其全部推到一起

或者如果你想坚持你原来的想法

(((1 to: 10) select: [ :each | (each rem: 3) = 0 ])
    inject: (WriteStream on: String new)
    into: [ :stream :each |
        stream
            nextPutAll: each printString;
            space;
            yourself ]) contents



不是总是这样,但遇到这种情况时最好记住。

您使用哪种方言?Dolphin、VW、VA、Pharo、Squeak、GNU……这些都是有效的,但我还是不太明白。是否有必要在第一个周期(在
ifFalse:
块中)返回
strm
,以使其“初始化”?忘记上面的注释,我理解。我接受了你的回答,你说得很对。此示例是我向同事展示的fizzbuzz实现的子部分,不能简化为
select:
reject:
String streamContents: [ :stream |
    (1 to: 10)
        select: [ :each | (each rem: 3) = 0 ]
        thenDo: [ :each |
            stream
                nextPutAll: each printString;
                space
        ]
]