第六章:FizzBuzz 问题

当然,当你接受面试的时候, Crystal 要你做的第一件事就是 FizzBuzz 问题!!!让我们开始吧

如果你还不熟悉 FizzBuzz 的话,它其实是一个简单的编程问题:

编写一个程序,打印数字 1 到 100.如果中途遇到 3 的倍数那么打 印 “Fizz” 替代这个数,同理如果遇到 5 的倍数打印 “Buzz” 替代这个数,如果既 是 3 也是 5 的倍数那么打印 “FizzBuzz” 替代这个数。

这个程序为面试官检验你的 Crystal 基础如:循环、测试、标准输出打印,等其他基础知识提供了很好的依据。

首先让我们创建一个项目.

$ crystal init app fizzbuzz

然后写我们的第一个失败 (failing) 的测试,打开 /spec/fizzbuz_spec.cr

require "./spec_helper"

describe Fizzbuzz do
  it "shouldn't divide 1 by 3" do
    div_by_three(1).should eq(false)
  end
end

运行它:

$ crystal spec
Error in ./spec/fizzbuzz_spec.cr:7: undefined method 'div_by_three'

div_by_three(1).should eq(false)

这是因为:我们还没有定义任何方法,让我们定义一个:

require "./fizzbuzz/*"

def div_by_three(n)
  false
end

与 Ruby 类似,最后一个语句的值会被返回。

TDD 的意思是做最简单的事,现在我们定义了一个方法,让我们编译并且运行:

$  crystal spec
.

Finished in 0.82 milliseconds
1 examples, 0 failures, 0 errors, 0 pending

真棒,我们通过了,再写另一个测试看看会发生什么

require "./spec_helper"

describe Fizzbuzz do
  it "shouldn't divide 1 by 3" do
    div_by_three(1).should eq(false)
  end

  it "should divide 3 by 3" do
    div_by_three(3).should eq(true)
  end
end

运行一下:

$ crystal spec

.F

Failures:

  1) Fizzbuzz should divide 3 by 3
     Failure/Error: div_by_three(3).should eq(true)

       expected: true
            got: false

     # ./spec/fizzbuzz_spec.cr:9

Finished in 0.83 milliseconds
2 examples, 1 failures, 0 errors, 0 pending

Failed examples:

crystal spec ./spec/fizzbuzz_spec.cr:8 # Fizzbuzz should divide 3 by 3

有一个错误,解决它:

require "./fizzbuzz/*"

def div_by_three(n)
  if n % 3 == 0
    true
  else
    false
  end
end

运行

$ crystal spec

..

Finished in 0.61 milliseconds
2 examples, 0 failures, 0 errors, 0 pending

溜溜溜,这个展示了 “else” 如何工作,正如你想要的,试试把它重构成一行呢

看看我的:

完成?你会怎么写,看看我的:

def div_by_three(n)
  n % 3 == 0
end

记住,最后一个语句的值会被返回。好啦,让我们 TDD 两个方法 divide_by_fivedivide_by_three,他们的原理是一样的, 但是下面的代码要试着写出完整程序了,一旦你看到了他们,说明你已经准备好了.

$ crystal spec -v

Fizzbuzz
  shouldn't divide 1 by 3
  should divide 3 by 3
  shouldn't divide 8 by 5
  should divide 5 by 5
  shouldn't divide 13 by 15
  should divide 15 by 15

Finished in 0.61 milliseconds
6 examples, 0 failures, 0 errors, 0 pending

好啦,现在让我们讨论下主程序,有了编写 FizzBuzz 的工具,让我们把它跑起来,第一件事就是打印数字 1 到 100,很简单

100.times do |num|
  puts num
end

第一步,打印 100 次,如果你通过这个: crystal build src/fizzbuzz.cr && ./fizzbuzz 运行,你会看见数字打印了100次。需要提醒的是我们的测试还没有运行,实际上不仅是没有运行,他们根本就不能执行,现在我们把两段代码耦合到一起:

现在我们可以把两者结合起来:

100.times do |num|
  answer = ""

  if div_by_fifteen num
    answer = "FizzBuzz"
  elsif div_by_three num
    answer = "Fizz"
  elsif div_by_five num
    answer = "Buzz"
  else
    answer = num
  end

  puts answer
end

由于 if 语句要返回值,所以我们因该这样:

(1..100).each do |num|
  answer = if div_by_fifteen num
    "FizzBuzz"
  elsif div_by_three num
    "Fizz"
  elsif div_by_five num
    "Buzz"
  else
    num
  end

  puts answer
end

注意我们把 100.times 改为 (1..100).each 令数字从 1 到 100 而不是 0 到 99。 试着运行一下。 很好我们已经拿下 FizzBuzz 了。

Last updated