如何在Pharo Smalltalk中实现开关

sum*_*ion 8 smalltalk switch-statement pharo

我正在尝试解析一个命令和一个int来在板上做一个"乌龟"移动.我有点不知所措,因为它没有抛出异常,我甚至无法弄清楚如何在没有它的情况下打开调试器.

我的代码:

"only should begin parsing on new line"
endsWithNewLine:= aTurtleProgram endsWith: String cr.
endsWithNewLine ifTrue:[
    "splits commands based on new lines"
    commands := aTurtleProgram splitOn: String cr.
    commands do:[:com |
        "should split into command and value for command"
        i := com splitOn: ' '.
        "command"
        bo := ci at: 1.
        val := ci at: 2.
        "value for command"
        valInt := val asInteger.
        ^ bo = 'down' "attempted switch"
            ifTrue: [ turtle down: valInt ]
            ifFalse: [
              bo = 'left'
                  ifTrue: [ turtle left: valInt ]
                  ifFalse: [
                    bo = 'right'
                        ifTrue: [ turtle right: valInt ]
                        ifFalse: [
                          bo = 'up'
                              ifTrue: [ turtle up: valInt ]
                              ifFalse: [ self assert: false ] ] ] ] ].
Run Code Online (Sandbox Code Playgroud)

Uko*_*Uko 10

您可以按照它的方式执行此操作,并且可以通过self halt在代码中插入语句来打开调试器.

通常,ifs,以及case-sytle ifs,都是一个坏兆头.所以你可以做的是打破功能到像类DownMove,LeftMove等等,然后当你调用,例如,每个类将实现其自身的功能execute:,会做什么用命令所需的方法.但在你的情况下,这种方法会很麻烦; 而且,你有非常微不足道的行动.

您可以使用带定义的字典.因此,假设您定义了一个实例变量或类变量:

moveActions := {
  'down' -> [ :dist | turtle down: dist ] .
  'left' -> [ :dist | turtle left: dist ] .
  ... } asDictionary
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中,你做:(moveActions at: bo) value: valInt.此代码段将为您提供字符串(键)的块(值),然后使用整数计算块.

另一方面,由于操作模式相同且只有消息发生更改,因此您只能映射字典中的消息名称:

moveActions := {
  'down' -> #down: .
  'left' -> #left: .
  ... } asDictionary
Run Code Online (Sandbox Code Playgroud)

然后你可以让你的乌龟用字符串动态地执行一条消息:

`turtle perform: (moveActions at: bo) with: valInt`
Run Code Online (Sandbox Code Playgroud)

此外,如果您想依赖于您读取的命令与发送给乌龟的消息之间的相似性,您可以动态组合消息字符串:

`turtle perform: (bo, ':') asSymbol with: valInt`
Run Code Online (Sandbox Code Playgroud)

请注意,在您的情况下不建议这样做,因为首先,您要耦合用户输入和代码,即如果您决定将用户命令从down更改为moveDown,则必须将方法名称更改down:moveDown:.此外,这种方法允许用户将错误代码"注入"到您的系统中,因为他可以编写一个命令become 42,这将导致代码:

`turtle perform: #become: with: 42`
Run Code Online (Sandbox Code Playgroud)

它将交换乌龟对象和42之间的指针.或者你可以考虑更糟糕的情况.但我希望这次元游览对你有好处.:)


Est*_*nLM 6

在Smalltalk中,您不使用switch语句.相反,你使用"案例方法"(我认为Ken Beck引入了术语,但我不确定).

在你的情况下,它会是这样的:

method1
    "only should begin parsing on new line"
    endsWithNewLine:= aTurtleProgram endsWith: String cr.
    endsWithNewLine ifTrue:[
    "splits commands based on new lines"
    commands := aTurtleProgram splitOn: String cr.
    commands do:[ :eachCommand | 
        | tuple direction value |

        tuple := eachCommand splitOn: ' '.
        direction := tuple first.
        value := tuple second asInteger.
        self moveTurtleDirection: direction value: value ].

moveTurtleDirection: direction value: value
    direction = 'down'  ifTrue: [ ^turtle down: value ].
    direction = 'left'  ifTrue: [ ^turtle left: value ].
    direction = 'right' ifTrue: [ ^turtle right: value ].
    direction = 'up'    ifTrue: [ ^turtle up: value ].

    self error: 'Invalid direction'.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这更清晰,您不需要应用"smalltalk magic"来实现高效设计.这也具有清晰,快速执行并且易于通过编译器 JIT进行优化的优点:)