yield和block总结

在ruby中以do...end包括的内容为block(代码块),如果只有一行可以用{...}.block无法单独存在,通常需要结合method使用.
比如平时使用最多的数组循环:

# 一个简单的迭代代码
[1,2,3,4,5].each do |item|
  p item
end

# 还可以这样子写
[1,2,3,4,5].each { |item| p item }

yield

在调用方法的时候,可以传递参数.有时候需要把一个代码块当作参数进行传递.这种时候可以使用yield实现.yield相当于占位符的概念,先把某一个代码过程中的位置占据,等待方法执行的时候根据传递的内容进行处理.
比如想统计一个很耗时的操作执行了多少时间,可以这样写:

# 时间方法执行间隔
def time_interval
  p "开始时间为:#{Time.now}"
  yield # 默认不需要参数
  p "结束时间为:#{Time.now}"
end

# 设置不同的时间间隔
time_interval { sleep(3) }
time_interval { sleep(5) }

执行结果

# 可以看到执行了以上代码之后,会执行sleep操作
"开始时间为:2018-04-04 09:52:37 +0800"
"结束时间为:2018-04-04 09:52:40 +0800"
"开始时间为:2018-04-04 09:52:40 +0800"
"结束时间为:2018-04-04 09:52:45 +0800"

可以看到上面的代码中,在调用time_interval方法的时候传递一个代码块作为一个默认参数,在方法内部使用yield把代码块放置在指定的位置.

通过yield调用方法的时候,可以传递参数.如:

def sum
  yield 3,5
end
sum { |a, b| p "#{a}+#{b}=#{a + b}" }

执行结果

"3+5=8"

proc

被调用的方法在需要传递参数的时候,代码块作为参数时,需要放在所有参数的最后面.在参数名字前面加上&符号,表示是一个代码片段参数.在调用的时候通过调用参数的call方法执行,如:

def log_msg(type, &b)
  p "当前的信息类型为#{type}"
  [1, 2, 3, 4].each do |item|
       b.call(item)
  end
end

myproc = proc { |t| p "执行了#{t}次" }
log_msg('写操作日志', &myproc)

执行结果

"当前的信息类型为写操作日志"
"执行了1次"
"执行了2次"
"执行了3次"
"执行了4次"

这里用到了关键字proc.使用block代码块的时候无法重复使用,代码块只能跟在方法调用后面.通过proc可以把需要执行的代码块进行保存,存为变量方面重复使用.

# 
myproc = proc { |t| p "执行了#{t}次" }

# 也可以这样子定义
myproc = Proc.new { |t| p "执行了#{t}次" } 

yield与block

通过上面的例子可以发现在使用代码块作为参数的时候,两者都可以用.下面通过一些简单的分析了解一下两者的区别

# 调用yield相当与调用block.call方法
def method_with_block(&block)
 p block.class
 yield
end

method_with_block { p '我在方法的块内' }

my_proc = Proc.new do
  p "这是定义的一个Proc实例"
  p "看下输出结果如何"
end
method_with_block &my_proc # 注意传递参数的时候一定要加&,否则会报错

执行结果

Proc                          # 方法块的class为Proc
"我在方法的块内"               # 

lambda

除了上面提到的两种写法之外还有lambda这种写法.

def arr_test(&l)
 # p l.class
  [1, 2, 3, 4].each do |item|
    yield item
  end
end
lambda1 = lambda { |n| p n*2 }
arr_test &lambda1

执行结果

2
4
6
8

上面的lambda可以写成如下的形式

lambda1 = lambda { |n| p n*2 }

# 或者这种写法
lambda1 = ->(n) { p n*2 }

通过输出lambda的class发现也是Proc

Proc

通过上面的一系列代码和例子可以发现,他们的class都是Proc对象,可以通过不同的方式进行定义.Proc 对象的定义有几种形式:

  • 直接使用 {}
  • 使用 Proc.new {}
  • 使用 proc {}
  • 使用 lambda {}

你可能感兴趣的:(yield和block总结)