Smalltalk 中的多个 if

Multiple ifs in Smalltalk

我是 smalltalk 的新手,仍在努力弄清楚基本的东西。下面是我写的一个简单的程序。 如果数字可以被 5 除则打印 "a",如果可以被 3 除则打印 "b",如果可以被 5 和 3 除则打印 "ab"。在任何其他情况下,程序只打印数字本身。 它当然是这样工作的,但我觉得代码不是很漂亮 - 我想避免第三个 "if",但我真的不确定如何。 你会如何重构这个?

1 to: 100 do: [ :i | 
  (i % 5 == 0)
  ifTrue: [ Transcript show: 'a' ].
  (i % 3 == 0)
  ifTrue: [ Transcript show: 'b' ].
  ((i % 3 == 0) or:  (i % 5 == 0))
  ifFalse: [ Transcript show: i ].
  Transcript cr.
].

在此先感谢您的帮助!

首先,我会将您的版本重写为:

1 to: 100 do: [:i |
    i % 5 = 0 ifTrue: [Transcript show: 'a'].
    i % 3 = 0 ifTrue: [Transcript show: 'b'].
    (i % 3 = 0 or: [i % 5 = 0]) ifFalse: [Transcript show: i].
    Transcript cr]

变化是:

  1. 使用 = 而不是 ==(没什么大不了的)
  2. 使用带括号的or: [i % 5 = 0]

您可以引入的另一个变化是

1 to: 100 do: [:i | | label |
    i % 5 = 0 ifTrue: [label := 'a'].
    i % 3 = 0 ifTrue: [label := 'b'].
    label isNil ifTrue: [label := i].
    Transcript show: label; cr]

请注意,我并没有过多关注 IF,而是关注 Transcript show: 在您的代码中出现了三次这一事实。

编辑

唉!我上面的版本不等同于你的,因为如果数字除以 53!

,它不会打印 'a'

编辑 2

下面是重现原始代码行为的方法:

1 to: 100 do: [:i | | label |
    label := ''.
    i % 5 = 0 ifTrue: [label := 'a'].
    i % 3 = 0 ifTrue: [label := label , 'b'].
    label isEmpty ifTrue: [label := i].
    Transcript show: label; cr]

闻起来像 Fizz Buzz 问题! :-)

我发现我喜欢的 Smalltalk (Pharo) 中的一种方法是使用字典,其中 Fizz and/or Buzz 词作为值,布尔值是否可以被 3 和 5 整除作为键。一旦你有了它,你只需查找 1 到 100 之间的每个索引的值。哦,不要自己除法和检查余数是否为零 - 它是 Smalltalk,所以一个数字应该知道它是否可以被另一个数字整除.

| fizzbuzz |
fizzbuzz := Dictionary
    with: #(true true)->'FizzBuzz'
    with: #(true false)->'Fizz'
    with: #(false true)->'Buzz'.
1 to: 100 do: [ :eachIndex |
    Transcript
        show: (fizzbuzz
            at: {eachIndex isDivisibleBy: 3. eachIndex isDivisibleBy: 5}
            ifAbsent: [ eachIndex ]);
        cr]

也看看其中的一些 other examples,有时不同的方法可能很有教育意义。我将留给您根据您的 'a'/'b'/'ab' 示例调整代码。