Detailed description of the code block and parameter transfer in Ruby, detailed description of ruby code transfer
1. Block Declaration
After the function is called, the block declaration is enclosed by {...}, Or do. end encapsulation. {} Is generally used in single-line statements, and do... end is used in multi-line statements.\
(1..4) .each {| v | print "# {v}"} #Output 1 2 3 4
Blocks can take parameters. Unlike function parameters, block parameters are encapsulated with ||. Of course, you can take multiple parameters. How to define these parameters is actually defined inside the function, which will be described later.
Second, the access of variables in the block
Blocks can access variables outside the block, that is, variables outside the block are visible inside the block, such as
sum = 0
(1..5) .each do | v |
name = 'smile' #name belongs to the variable within the block, and its visible range can only be within the block. Suppose there are no variables with the same name outside the block.
sum = v #sum is visible inside the block
end
p sum #Output 15, sum has changed.
p name #Error! name is not accessible.
Because of the variables inside and outside the block, some external variables may be accidentally modified, which is not what we want. Fortunately, after the Ruby 1.9 version, it provides a safe way to declare variables in the block, adding ";" after the block parameters, and placing the variables in the block after ";"
name = 'outside'
sum = 0
(1..5) .each do | v; name | #nameAfter ";", you can declare multiple variables, separated by commas
name = 'inside' #name belongs to a variable within the block, and its visible range can only be within the block. Assume that there is no variable with the same name outside the block.
sum = v #sum is accessible within the block
end
p sum #Output 15, sum has changed.
p name #Output outside without change.
Third, the yield statement
Looking here, it may not be clear how the function calls the block. Now to introduce the call of the block, the key is the yield statement. In the function body, if yield is used, the function will call the function block.
def threeTime
yield
yield
yield
end
threeTime {p 'Hello world!'}
Is it easy to output three lines of Hello world! You should understand now, it is the block called by yield.
What are the parameters of the block? It is estimated that you have thought of the yield parameters, which can take parameters like the general function. See example
def takeBlock (p1)
if block_given? # Determine whether there is a block. If there is no block declared during yield, an error will occur, so it will be better to make a judgment here.
yield (p1) # P1 is passed to the block parameters, that is, s
else
p1
end
endie
takeBlock ("no block") #output "no block"
takeBlock ("no block") {| s | s.sub (/ no /, '')} #output "block"
Since yield can pass parameters to the block, in turn, can the block pass values to yield? The answer is yes. The value of the last sentence in the block is automatically passed to yield. See example
def nTime
i = yield #When the first call, return the value of the block
(0..i) .each {| v | yield (v)} # Here yield can also be placed in a block
end
nTime do | v |
print "# {v}" if v
9 #yield Number returned when called
end
#Output 1 2 3 4 5 6 7 8 9
Of course, the above example is just used as an example. In fact, no one would define it this way. A better definition is as follows:
def nTime (n)
(0..n) .each {| v | yield (v)}
end
nTime (9) do | v |
print "# {v}"
end
Let's take a look at the find implementation in Array
class Array
def find
for i in 0 ... size
value = self [i]
return value if yield (value)
end
return nil
end
end
[1, 3, 5, 7, 9] .find {| v | v> 5} #Realize finding the first number greater than 5, and output 7.
Because of the appearance of blocks, many for statements are missing in Ruby, and the code looks more user-friendly. Writing code is no longer a boring thing, but a pleasure.
Four, another way to pass blocks
def fun #without parameters
yield
end
proc =-> {p 'haha'}
fun & proc
#####
def fun2 (x) #with parameters
yield x
end
proc2 =-> (x) {p x}
fun2 1, & proc2
Five, instance_eval () and instance_exec ()
In Ruby, a very cool feature is provided. You can use the Objec # instance_eval (), Objec # instance_exec () method to insert a code block and make an object context probe (Context Proble) to drill into the code in the object Fragment, operate on it. With this feature, you can easily test the behavior of the object and view the current state of the object.
class MyClass
def initialize
@v = 1;
end
end
obj = MyClass.new
obj.instance_eval do
puts self # => # <MyClass: 0x007fbb2d0299b0>
puts @v # => 1
end
obj.instance_exec (5) {| x | puts x * @v} # => 5