可见#inject:into:block

时间:2016-07-15 04:04:48

标签: smalltalk

此代码:

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

失败,因为strm未定义ifTrue:块中使用的位置。为什么在那里看不到?

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

2 个答案:

答案 0 :(得分:4)

问题是隐含的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 :(得分:4)

根据方言(可用的方法),您可以采用更短的方法

((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
        ]
]

¹并非总是如此,但在遇到这种情况时总是要记住。