ruby block & proc & lambda

Keywords: Lambda Ruby

List contents

First, what is block in ruby?

Block is a general term, Chinese name is also called closure, English is Closure, in the form of block, Proc and
Lambda. Proc is an object-oriented encapsulation of block, lambda is a further encapsulation of Proc.

block Writing Style

Braces + code {p'hi'} do... end, which is also a block of code

Two, block
Although everything in Ruby is an object, a block exists as a feature, not an object.
Look at the following code:

> 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}" }

Simply put, the following expressions of each are blocks. The example above is the block method that calls the Array object. It seems mysterious, but we can also define a block method for our class.

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 }

The results are simple: 1, 2, 3, 4

Now that we've talked about customization, we can't end this way. We can be a little more complicated.

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}" }

The results are as follows:
number at 0 has value 1
number at 1 has value 2
number at 2 has value 3
number at 3 has value 4

Next, I have to talk about the key word yield. Let's start with a simple example.

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!" }

Ignore 1, 2, 3, 4, the above example will only output yield is also sexy!, that is to say, all the content behind a.my_yield goes to my_yield, replacing yield, simple.

Start upgrading it below:

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}
}

The output is as follows:
yield with parameter!
1
2
3
4
If you're not an expert, I'm sure you'll go back and review the code. What happened in my_yield? In fact, it's not difficult, as in the example above, to replace yield with @my_arr and replace my_tmp_arr with @my_arr.

Three, Proc
As mentioned earlier, Proc is Ruby's object-oriented encapsulation of blocks. In short, I define a block that I can reuse many times. Let's take an example. For example, I want to calculate the area of a rectangle.

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

If I want to fix the long side, just input the width, then I can add a parameter:

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

Four, lambda
lambda is actually a function of Ruby to create Proc.

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

5. Differences between proc and lambda
There are two main differences:

First, lambda checks the parameters, but Proc does not.

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

Second, lambda returns its calling function, but Proc terminates its function.
This sentence is not very easy to understand. It is also the difference between block and lambda. Lambda is essentially a function, so it will return from lambda when it comes to return. Proc is a code that can be executed, which is equivalent to inserting a break code into the function. When the return statement is included in proc, the whole function will return.

def return_from_proc
  ruby_proc = Proc.new { return "return from a Proc" } 
  //  Equivalent to return "return from a Proc"  This is equivalent to jumping out of this function.
  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" }
  //Equivalent to def ruby_lambda return "return from lambda"  end  TherereturnIt's like jumping out of this. ruby_lambda The following statement of the function will also be executed
  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

6. How do blocks be converted into proc objects?

1.Proc.new + code block

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

2.proc + code block (proc abbreviation)

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

3.lambda + Code Block

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

4. -> + Code Block (lambda abbreviation)

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

Summary: Block is not an object, but a code block. It can be imagined as an instance object of proc. It can only call proc once to encapsulate the block further and reuse it.
lambda's further encapsulation of proc is actually a function, more rigorous, that checks parameters

Posted by Adika on Thu, 27 Dec 2018 10:36:06 -0800