Proc#call
Proc#call
, the lambda
construct, as well as the concepts of a class instance variable (instances variables are variables whose names begin with the dog) and class variables (class variables are variables whose names begin with two dogs):
Proc
Proc
- class for blocks that can be called unnamed (anonymous) methods that can be created directly in expressions;b.call(*args)
expression executes b
, and returns the result of the execution; instead of call you can use square brackets.lambda {|a,...| ... }
lambda {|a,...| ... }
- creates a block, for example b = lambda {|x,y,z| x+y+z}
b = lambda {|x,y,z| x+y+z}
will create a block that adds three numbers, in particular, the expression b[1,2,3]
will return 6
;{ ... }
or do ... end
; for example ary.inject{|a,b| a * b}
ary.inject{|a,b| a * b}
will pass inside the inject
method a block that multiplies two numbers;Exception
“ uninitialized class variable .. in ...
” occurs;a = 1 <br>
b = lambda { puts a }<br>
b.call # 1 <br>
a = 2 <br>
b.call # 2 <br>
# - <br>
class Abc <br>
attr_accessor :bar <br>
def foo <br>
@bar ||= 0 <br>
x = 5 <br>
lambda { puts @bar , x, self .class; }<br>
end <br>
end <br>
<br>
x = 10 <br>
a = Abc .new<br>
b = a.foo<br>
b.call # 0, 5 Abc <br>
a.bar += 1 <br>
x = 10 <br>
b.call # 1, 5, Abc <br>
# bar a b, <br>
# ( ) -- <br>
# ; - <br>
# foo, @a x, <br>
# , <br>
# , foo . <br>
<br>
lambda
or with a block passed to the method, either with braces or with a do ... end
construct.
foo
method on the instance a of some class Abc
.
@bar
and a block is returned, which
x
and self.class
.
b.call
" is b.call
, the @bar
variable @bar
not visible (or rather, it simply does not exist in this context).
b
block leads to the output of the variable @bar
object a
, which, as it were, is not suitable here. This is explained by the fact that the block was created in the context of the execution of the foo
method of the object a
, and in this context all the instance variables of the object a
were visible.
class Abc <br>
attr_accessor :block <br>
def do_it <br>
@a = 1 <br>
block.call<br>
end <br>
end <br>
<br>
c = 1 <br>
a = Abc .new<br>
a.block = lambda { puts " c= #{ c } " }<br>
a.do_it # 1; <br>
# - <br>
# <br>
<br>
a.block = lambda { puts " @a= #{ @a .inspect } " }<br>
a.do_it # nil, .. @ , <br>
# " " a.block. <br>
# a.block Abc#foo <br>
# Abc#foo a.block <br>
lambda
construction:
class Abc <br>
def do_it (&block)<br>
@a = 1 <br>
block.call<br>
end <br>
end <br>
<br>
c = 1 <br>
a = Abc .new<br>
a.do_it {puts " c= #{ c } " } <br>
a.do_it { puts " @a= #{ @a .inspect } " }<br>
<br>
self
equal to this object are visible from the body of the method. Instance variables of other objects are not visible.
self
as some method that can be defined in its own way in each context.
def
and class
constructs. They usually lead to a change in the visibility of the instance variables, class variables and a change in the value of the expression self
.
Ruby
- this is an object of class Binding
Binding
Each block has a binding
, and this binding
can be passed as the second argument to the eval
method: “run this code in this context”:
class Abc <br>
attr_accessor :x <br>
def inner_block <br>
lambda {| x | x * @factor }<br>
end <br>
end <br>
<br>
a = Abc .new<br>
b = a.inner_block<br>
eval ( " @factor = 7 " , b.binding)<br>
puts b[ 10 ] # 70 <br>
eval ( " @x = 6 * @factor " , b.binding)<br>
puts ax # 42
instance_eval
:
class Abc <br>
attr_accessor :x <br>
end <br>
<br>
a = Abc .new<br>
a.instance_eval( " @factor = 7 " )<br>
a.instance_eval( " @x = 6 * @factor " )<br>
puts ax # 42
Binding
class object) to the concept of a real context, we need to store both the call stack and all objects that are in this stack, and this becomes a real problem. Example of access to the call stack:
def backtrace <br>
begin <br>
raise Exception .new( '' )<br>
rescue Exception =>e<br>
e.backtrace[ 1 ..- 1 ]<br>
end <br>
end <br>
<br>
def f <br>
g<br>
end <br>
<br>
def g <br>
puts backtrace.join( " \n " )<br>
end <br>
<br>
f<br>
<br>
make_rescued.rb: 15: in `g ' make_rescued.rb: 11: in `f ' make_rescued.rb: 18
ary.map{|i| i*i}
ary.map{|i| i*i}
or users.map{|u| e.email}
users.map{|u| e.email}
, I would not want to deal with closures. But often it is simply not possible to predict that from the visible namespace will be used by the block, since, in principle, an eval
or a method call with an associated block, which, in turn, can request the block.binding
value passed to it, can occur in a block
. do with him what he wants. You should also be afraid of the send(m, *args)
expression, since this can be send('eval', *args)
. It is possible to create a block with a minimal context as follows: " block = class << Object.new; lambda { ... } end
". Perhaps it makes sense to optimize (first of all I want to get rid of the call stack clinging to the closures) to come up with a new language construct like glob_do ... end
to create blocks whose general context is a global context in which self
is equal to the special main
object.Source: https://habr.com/ru/post/50665/