在#inject:into: 块中可见

Visibilily in #inject:into: block

此代码:

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

失败,因为 strmifTrue: 块中使用的地方未定义。为什么在那里看不到它?

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

问题是隐含的 ifFalse: 分支 returns 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: ' '

根据经验¹,任何 collection do: [ :each | something ifTrue: [] ] 都可以变得更加直接和可读 collection select: []collection reject: []

这样做会将复杂性分散到几个独立的步骤(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

String streamContents: [ :stream |
    (1 to: 10)
        select: [ :each | (each rem: 3) = 0 ]
        thenDo: [ :each |
            stream
                nextPutAll: each printString;
                space
        ]
]

¹所以并非总是如此,但遇到这种情况时请牢记。