代码块
终于来到代码块的知识,其实这个函数式编程语言中比较晦涩难懂的一部分。其实,我们在举method_missing方法例子的时候已经用过一次块。这里再举一个更直观的例子:
blocks/basics_failure.rb
def a_method(a,b)
a + yeild(a, b)
end
a_method(1,2) { |x, y| (x+y)*3 } #=>10
代码块可以用大括号定义,也可以用do…end关键字定义,通常,只用一行的块用的是大括号,而多行的块用的是do…end。 只用在调用一个方法时,才可以定义一个块。 这里的yeild主要是起到一个占位的作用。
在一个方法中,我们还可以询问当前的方法调用是否包含块。可以用过Kernel#block_given?方法做到。
def a_method
return yield if block_given?
'no block'
end
a_method
a_method { 'here 's a block' }
代码块闭包
代码块不是浮在空中的,它不可能独立地运行。运行代码需要一个执行环境:局部变量,实例变量,self等。由于这些东西都是绑定在对象上的名字,所以把它们简称为绑定,代码块之所以可以运行,是因为它既包含代码,也包含一组绑定。
当块被传入一个方法时,它会带着这些绑定一块进入该方法:
blocks/blocks_and_bindings.rb
def my_method
x = "Goodbye"
yield("cruel")
end
x = "Hello"
my_method { |y| "#{x}, #{y} world" } # => "Hello, cruel world"
在上面的例子中,代码块的绑定中包含一个名为x的变量。虽然在方法中也定义了一个变量x,但代码块看到但x还是在代码块定义时绑定但x,方法中的x对这个代码块来说是不可见的。
我们还可以在代码块内部定义额外的绑定,但是这些绑定在代码块结束时就消失了:
blocks/block_local_vars_failure.rb
def just_yield
yield
end
top_level_variable = 1
just_yield do
top_level_variable += 1
local_to_block = 1
end
top_level_variable #=>2
local_to_block #=>Error!
基于这样的特性,我们将代码块称之为闭包。换句话说,代码块可以获取局部绑定,并一直带着它们。