我不知道为什么这个 Ruby 斐波那契数列有效

I don't know why this Ruby Fibonacci sequence works

我正在编写一个程序,使用 Ruby 将斐波那契数列推入数组。代码有效,但我无法理解 为什么 它有效。

这部分我明白了,就是斐波那契方程:

fib_array = []

def fib (n)
    return n if n <= 1
    fib(n - 1) + fib(n - 2)
end

这是我不明白的地方:

10.times do |x|
    fib_array << fib(x)
end

print fib_array

我写了这个抓住救命稻草,它有效。我不明白为什么。我没有给它一个开始的数字,Ruby 是不是意味着 0?另外,它怎么知道复合数字而不是打印 [0, 0, 0...]?如果这是一个愚蠢的问题,我深表歉意,但我不知所措。

看起来底部的代码只是调用 x=0, x=1 ... x=9 上的 fib 函数并将它的 return 值存储在数组的末尾。当使用迭代变量 (x) 调用 times 时,它从 0 开始并在循环的每次迭代中递增。你从来没有给它一个值,但是它成功地解决了迭代变量 x 作为参数传递给 fib.

的问题

代码的第二部分说:

"From the instance 10 of the class Integer, call the method times with the given block"(方法"recive"隐含一个块)。

什么是区块? {braces}do-end 之间的一小段代码(就像您所做的那样)。

方法 times 被调用,"iterator"。它会 yield 0,1,2,..,9(在你的情况下)。迭代器和 yield 语句总是在一起的。认为yield就像return有记忆,当你寻找更多信息时。

因此,您的代码可以重写为:

10.times { |x| fib_array << fib(x) }

它会在方法 times 的每个 yield 上调用你传递的块 做。调用方法 <<(追加)到数组上 fib(x) 的结果。

我们有:

def fib (n)
  return n if n <= 1
  fib(n - 1) + fib(n - 2)
end

你懂的。首先让我们看看前 5 个斐波纳契数是什么::

fib_array = []
5.times do |x| 
  fib_array << fib(x)
end
fib_array
  #=> [0, 1, 1, 2, 3]

现在让我们分解一下,看看会发生什么。首先查看方法 times 的文档。要找到它们,我们需要知道方法来自哪个 class 或模块,因为这就是文档的组织方式。作为 5.class #=> Fixnum,我们可能会查看 Fixnum 的文档。嗯。 times 不存在。显然,它是从另一个 class 继承而来的。让我们检查一下:

Fixnum.ancestors
  #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject] 

Integer包括FixnumBigNumNumeric包括IntegerFloat(3.14).times 没有意义,所以 times 似乎是在 Integer 中定义的,所以它是:Integer#times。通过在那里定义它,它被 FixnumBignum.

继承

这是确定方法来源的直接方法:

5.method(:times).owner #=> Integer

现在理解这一点并不重要,但是随着您获得使用 Ruby 的经验,您会发现它很方便。

好的,文档说 times return 如果给定块则为值,否则为枚举器。让我们暂时忘记块,看看 returned:

的枚举器
enum = 5.times         #=> #<Enumerator: 5:times> 

方法 Enumerator#each 将枚举器 enum 的元素传递给它的块:

do |x| 
  fib_array << fib(x)
end

将它们分配给块变量x。要查看枚举器的内容,请将其转换为数组:

enum.to_a           #=> [0, 1, 2, 3, 4] 

结果是:

fib_array = []
enum.each do |x| 
   fib_array << fib(x)
end
fib_array
  #=> [0, 1, 1, 2, 3]

这当然与我们之前获得的结果相同。现在让我们通过使用方法 Enumerator#next 提取枚举器的每个元素来逐步了解发生了什么:

x = enum.next       #=> 0 
fib(x)              #=> 0 
fib_array << fib(x) #=> [0] 

x = enum.next       #=> 1 
fib(x)              #=> 1 
fib_array << fib(x) #=> [0, 1] 

x = enum.next       #=> 2 
fib(x)              #=> 1 
fib_array << fib(x) #=> [0, 1, 1] 

x = enum.next       #=> 3 
fib(x)              #=> 2 
fib_array << fib(x) #=> [0, 1, 1, 2] 

x = enum.next       #=> 4 
fib(x)              #=> 3 
fib_array << fib(x) #=> [0, 1, 1, 2, 3] 

print fib_array     # [0, 1, 1, 2, 3]

仅此而已。