Ruby 中的闭包-代码块

看了一片文章https://ruby-china.org/topics/38385讲closure的。

写下一些感想:

闭包就是 一个函数能够记住和存取它的lexical作用域,即使这个函数是在它的lexical作用域的外面执行。

当一个函数被写出来时,这个函数的closure就已经确定了。

 

javascript中有闭包的概念:https://www.cnblogs.com/chentianwei/p/9739714.html

Ruby中的关键字定义def是没有闭包的。它创建一个封闭的作用域。

但是Ruby有闭包的概念这就是--代码块。

a = 100

define_method :add_a do
  a = a + 1
end

puts add_a # => 101
puts add_a # => 102
puts add_a # => 103

 这个例子使用了define_method方法搭配一个代码块来定义方法。我们就可以访问外部的作用域的局部变量a。

Ruby就是使用代码块来表示闭包的。 

 可以参考《Ruby元编程》相关章节的例子:

def my_method
  x = "GoodBye"
  puts yield("cruel")
end

x = "Hello"
my_method  do |y|
  "#{x}, #{y} world!"
end

 

代码块绑定了变量x。即外部作用域的变量跟着代码块一起走!

 

代码块的意义:

在Ruby的开源世界,代码块无处不在:

1.容错涉及:

Ruby承袭于Lisp,代码块的运行会自动返回最后一条语句或者表达式的值,于是有些库也考虑到了用代码块来进行容错处理。

例子:

> hash = {}
> value = hash.fetch('a') { 'default value' }
 => "default value"

 

因为hash是空的,没有"a", 所以会返回代码块中的字符串,如果不提供代码块,就会报错❌。

 

2. DSL

3. 蹩脚的函数

代码块可以看作是一个蹩脚的函数,虽然一般情况下可以作为某个方法的回调,但在Ruby中代码块需要依赖其他机制来存在,而不是JS中的函数那样独立存在。

当使用代码块来定义一个匿名函数时,需要搭配lambda关键字或Proc类来实现。

> c = lambda() {}
 => #<Proc:0x00007ff47b8546a8@(irb):6 (lambda)>
> c.class
 => Proc

> (lambda() { 'hello' }).call
 => "hello"
> (lambda() { 'hello' })[]
 => "hello"
> (Proc.new { 'hello' }).call
 => "hello"
> (Proc.new { 'hello' })[]
 => "hello"

x = "tom"
(lambda() {"Hello,#{x}"}).call 

以上都是常用的定义匿名函数的方式,本质上它们都是Proc类的实例,需要显式地利用Proc#call方法或者语法糖[]来调用它们。

 

总结:

这篇文章介绍了Ruby中的闭包概念, 它和封闭作用域的方法(使用def关键字定义的方法)有什么不同。

⚠️ Ruby中定义了三个地方为封闭的作用领域(对应三个关键字):

  • 类定义 class
  • 模块定义 module
  • 方法def

区别于一般的方法,闭包在Ruby中以代码块的形式出现,它在Ruby世界中几乎无处不在,充当了一等公民。这种区分,不仅使我们的Ruby代码更加优雅,增添了可读性,还使得我们的编码过程更加简单。

 

posted @ 2019-08-31 11:46  Mr-chen  阅读(504)  评论(0编辑  收藏  举报