Yield
All "Method (methods)" implicitly follow a "block" parameter.
The block parameter can also be given explicitly, in the form of a "&" in front of the parameter, such as DEF fn (Arg1, arg2, &block) end, where the &block is explicitly given the block parameters.
The action of the block parameter can be executed by invoking the call () method, and can be executed using yield to--yield is actually a syntactic sugar.
So the following types of writing are often equivalent:
#method receives an invisible block argument
def foo1()
yield 1
end
#specify it explicitly
def foo2(&block)
yield 1
end
#yield is equal to block.call
def foo3(&block)
block.call(1)
end
#function call
foo1 {|x| puts x} # => 1
foo2 {|x| puts x} # => 1
foo3 {|x| puts x} # => 1
Proc
In the previous case, all methods can implicitly or explicitly specify a block parameter, so what is the block parameter exactly?
The answer is a Proc object, an object with a call method.
Proc objects are defined in several forms:
- Use {} directly
- Use Proc.new {}
- Use proc {}
- Using Lambda {}
#yield is equal to block.call
def foo(&block)
puts block.class
puts block.to_s
yield 1
end
#function call
# Proc created using {} syntax
foo {|x| puts x}
# => Proc
# => #<Proc:[email protected](ruby):9>
# => 1
# Proc created with the "proc" keyword. Note & syntax when calling.
my_proc = proc { |n| puts n }
foo(&my_proc)
# => Proc
# => #<Proc:[email protected](ruby):12>
# => 1
# Proc creates with Proc.new
my_proc = Proc.new { |n| puts n }
foo(&my_proc) # => 1
# => Proc
# => #<Proc:[email protected](ruby):16>
# => 1
# Proc created with the "lambda" keyword. Nearly same thing.
my_proc = lambda { |n| puts n }
foo(&my_proc)
# => Proc
# => #<Proc:[email protected](ruby):20 (lambda)>
# => 1
Yield self
In an object, self represents a reference to the current object.
So, the common yield self if block_given? Self in the same way as other places, there's nothing special about it.
class C1
def foo(&block)
puts block.class
puts block.to_s
yield self if block_given?
yield "AAAAAAAAA"
end
end
class C2
def foo(&block)
puts block.class
puts block.to_s
yield self if block_given?
yield "BBBBBBBBB"
end
def to_s
"XXXXXXXXXX"
end
end
c1 = C1.new
c1.foo {|x| puts x}
# => Proc
# => #<Proc:[email protected](ruby):23>
# => #<Context::C1:0x00000001c84af0>
# => AAAAAAAAA
c2 = C2.new
c2.foo {|x| puts x}
# => Proc
# => #<Proc:[email protected](ruby):26>
# => XXXXXXXXXX
# => BBBBBBBBB
Precautions
The &block parameter in the method definition must be in the last
# Correct example
def foo (arg1, arg2, & block)
puts block
end
#function call
block = proc {| x | puts x}
foo (1, 2, & block)
# => # <Proc: [email protected] (ruby): 14>
#Error example
def foo (arg1, & block, arg2) # => (ruby): syntax error
puts block
end
Yield is equivalent to the call of the Block.call () method, so the number of parameters also needs to correspond
def foo ()
yield 1,2,3 # where 1 2 3 is the parameter passed
end
#function call
foo {| x | puts x} # => 1
foo {| x, y, z | puts z} # => 3
foo {| x, y, z, k | puts k} # is empty
The--yield and yield self of Ruby's problematic points