是的,它使用递归。如果我们查看 {} 括号中的代码,我们可以找出答案。让我们开始看看哈希。new 关键字后面的值是默认值。如果散列中尚不存在该值,则将分配该值。
hash = Hash.new
p hash['new_value'] #=> nil
default_value_hash = Hash.new(0)
puts default_value_hash['new_value'] #=> 0
hash_with_block = Hash.new{|h,x| x}
puts hash_with_block['new_value'] #=> 'new_value'
所以当我们声明
fibonacci = Hash.new{ |h,x| h[x] = x < 2 ? x : h[x-1] + h[x-2] }
我们基本上是在说 - 创建一个具有默认值的新哈希。如果我们要求一个小于或等于 2 的数字 (x),只需返回输入 (x)。否则,给我们键为 x-1 和 x-2 的字典值的总和。基本上是斐波那契算法。如果 x-1 和 x-2 不存在,它会再次运行相同的代码,直到两个基本输入值分别为 1 和 2。
这两种方法的区别在于散列保存了值(在散列中......)。在某些情况下,这可能是一个巨大的优势。每次调用 lambda 时,它都需要重新计算低于调用值的所有数字的值。
# Let's create a counter to keep track of the number of time the lambda is called.
# Please do not use global variables in real code. I am just lazy here.
@lambda_counter = 0
fibonacci_lambda = ->(x){
@lambda_counter += 1
x < 2 ? x : fibonacci_lambda[x-1] + fibonacci_lambda[x-2]
}
p (1..20).map{|x| fibonacci_lambda[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p @lambda_counter # => 57290
# lambda called 57290 times!
@hash_counter = 0
fibonacci_hash = Hash.new{ |h,x|
@hash_counter += 1
h[x] = x < 2 ? x : h[x-1] + h[x-2]
}
p (1..20).map{|x| fibonacci_hash[x]}
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
p @hash_counter # => 21
# Only called 21 times!
调用差异很大的原因是递归的性质。lambda 不存储其值,当计算 10 的值时,它会重新计算 3 的值超过 20 次。在散列中,这个值可以被存储并保存以备后用。