ruby block & proc & lambda

列表内容

一、什么是ruby中的block?

Block是一个统称,中文名称又叫闭包,英文是Closure,表现形式有block, Proc and
lambda。Proc是对block的面向对象的封装, lambda是对Proc的进一步封装。

block书写方式

大括号+代码 { p ‘hi’} do … end,也是代码块

二、block
虽然Ruby中万物皆对象,但block是作为一个特性而存在,不是对象
看如下代码:

> my_array = [ 1, 2, 3, 4, 5 ] my_array.each { | number | puts number}
> my_array.each do | number |   puts number end my_array.each_index { |
> index | puts "number has #{index}" }

简单来说,each后面的几种表达就是block,上面的例子就是调用Array对象的block方法。看起来好像很神秘,其实我们也可以为自己的类定义一个block方法。

class MyArray
  attr_accessor :my_arr
  def initialize( my_arr )
    @my_arr = my_arr
  end

  def my_each( &my_block )
    for i in 0..@my_arr.length-1
      my_block.call( @my_arr[i] )
    end
  end
a = MyArray.new( [1,2,3,4] )
a.my_each { | number | puts number }

结果很简单: 1,2, 3,4

既然已经说到自定义了,不能这样就结束了,我们可以再复杂一点:

class MyArray
  attr_accessor :my_arr
  def initialize( my_arr )
    @my_arr = my_arr
  end

  def my_each( &my_block )
    for i in 0..@my_arr.length-1
      my_block.call( @my_arr[i], i )
    end
  end
end

a = MyArray.new( [ 1, 2, 3, 4 ] )
a.my_each { | number, index | puts "number at #{index} has value #{number}" }

结果如下:
number at 0 has value 1
number at 1 has value 2
number at 2 has value 3
number at 3 has value 4

接下来不得不说一下yield这个关键字,我们从简单的例子开始

class MyArray
  attr_accessor :my_arr
  def initialize( my_arr )
    @my_arr = my_arr
  end

  def my_yield
    yield
  end
end

a = MyArray.new( [ 1, 2, 3, 4 ] )
a.my_yield { puts "yield is also sexy!" }

请大家无视1,2,3,4, 上面的例子只会输出yield is also sexy!, 也就是说 a.my_yield 后面的所有内容都跑到 my_yield 中,替换了 yield,简单吧。

下面开始对其升级:

class MyArray
  attr_accessor :my_arr
  def initialize( my_arr )
    @my_arr = my_arr
  end

  def my_yield
    yield( @my_arr )
  end
end

a = MyArray.new( [ 1, 2, 3, 4 ] )
a.my_yield {| my_tmp_arr |
  puts "yield with parameter!"
  my_tmp_arr.each{| number | puts number}
}

输出如下:
yield with parameter!
1
2
3
4
如果你不是高手,我相信你会回头再品一下代码的,这个my_yield中到底发生了什么事?其实也不难,按照上例中的,把a.my_yield后面的全部甩到my_yield中替换yield, 然后用@my_arr替换my_tmp_arr就可以了。

三、Proc
前面说到Proc是Ruby对block的面向对象的封装,简单来说,就是我自己定义一个可以多次重用的block。还是看个例子吧,比如我想计算一个长方形的面积:

rectangle_area = Proc.new{ | a, b | puts a * b }
rectangle_area.call( 5, 6 )

如果我的想固定长边,只输入宽度就好了,那我可以加入一个参数:

def rectangle_area_with_length (length)
  Proc.new{ | width | width * length }
end

area = rectangle_area_with_length(6)
area.call(3)
area[3]
area.class # => Proc

四、lambda
lambda其实是Ruby的一个函数,用来创建Proc。

multiply_lambda_proc = lambda { | x, y | x * y }
multiply_lambda_proc.call( 3, 4 ) # return 12

五、proc和lambda区别
主要有两个不同点:

第一,lambda 会检查参数,而 Proc 不会。

multiply_lambda_proc = lambda { | x, y | x * y }
multiply_proc = Proc.new { | x, y | x * y }

multiply_lambda_proc.call( 3, 4, 5 ) # ArgumentError: wrong number of arguments (3 for 2)
multiply_proc.call( 3, 4, 5 ) # return 12 as normal
multiply_proc.call( 3 )  # TypeError: nil can't be coerced into Fixnum

第二,lambda 会返回它的调用函数,但 Proc 会结束它所位于的 function。
这句话不太好理解,说白了也是block与lambda的区别,lambda本质上是函数,所以遇到return时会从lambda函数内返回,而proc是一段能执行的代码,相当于你在函数中插入一段断码,当proc中包含return语句时,导致整个函数就返回了

def return_from_proc
  ruby_proc = Proc.new { return "return from a Proc" } 
  //  等价于 return "return from a Proc"  这里相当于跳出了这个函数
  ruby_proc.call
  return "The function will NOT reach here because a Proc containing a return statement has been called"
end

def return_from_lambda
  ruby_lambda = lambda { return "return from lambda" }
  //等价于def ruby_lambda return "return from lambda"  end  这里的return相当于跳出了这个ruby_lambda 函数下面语句还会执行
  ruby_lambda.call
  return "The function will reach here"
end

puts return_from_proc # display return from proc
puts return_from_lambda # display The function will reach here

六、块怎样转换成proc对象?

1.Proc.new + 代码块

Proc.new { |imsi| where(imsi: imsi) }

2.proc + 代码块(proc缩写)

proc { |imsi| where(imsi: imsi) }

3.lambda + 代码块

lambda{ |rs| where.not(report_status: rs) }

4.-> + 代码块(lambda缩写)

--> (rs) { where.not(report_status: rs) }

总结: block不是对象,就是一个代码块,可以想象成proc的实例对象,只能调用一次 proc的对block进一步封装,可以进行复用
lambda的对proc进一步封装,其实是一个函数,更严谨,会检查参数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值