В Ruby self
имеет лексическую область, то есть self
внутри блока или лямбды - это то, что было бы в том же месте, не будучи в блоке или лямбде.
class << foo = Object.new
def bar
puts "`self` inside `foo#bar` is #{self.inspect}"
yield self
end
end
this = self
foo.bar do |that|
puts "`self` inside the block is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the block."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the block is main
# … which is the same as outside the block.
Это такжеприменяется к лямбдам:
class << foo = Object.new
def bar(lambda)
# ↑↑↑↑↑↑↑↑
puts "`self` inside `foo#bar` is #{self.inspect}"
lambda.(self)
#↑↑↑↑↑↑↑↑↑↑↑↑
end
end
this = self
foo.bar(-> that do
# ↑↑↑↑↑↑↑↑
puts "`self` inside the lambda is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the lambda."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end)
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the lambda is main
# … which is the same as outside the lambda.
Там есть , однако фиксированное количество очень специфических отражательных методов, которые делают изменяют self
, это методы всемейство *_{exec|eval}
:
Пример (изменение только одной соответствующей строкисверху):
class << foo = Object.new
def bar(&blk)
# ↑↑↑↑↑↑
puts "`self` inside `foo#bar` is #{self.inspect}"
instance_exec(self, &blk)
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
end
end
this = self
foo.bar do |that|
puts "`self` inside the block is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the block."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the block is #<Object:0xdeadbeef48151623>
# … which is the same as inside the method.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Это также относится к лямбдам (преобразованным в блоки):
foo.bar(&-> that do
# ↑↑↑↑↑↑↑↑
puts "`self` inside the lambda is #{self.inspect}"
case
when this.equal?(self)
puts "… which is the same as outside the lambda."
when that.equal?(self)
puts "… which is the same as inside the method."
else
puts "Ruby is really weird, `self` is something completely different!"
end
end)
# `self` inside `foo#bar` is #<Object:0xdeadbeef48151623>
# `self` inside the lambda is #<Object:0xdeadbeef48151623>
# … which is the same as inside the method.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Наконец, Ruby позволяет вам рефлексивно изменять лексическую среду на определенном сайте вызова. в Binding
объект. Затем вы, в свою очередь, можете оценить код в контексте этой конкретной привязки, используя метод привязки Binding#eval
или передав объект привязки в Kernel#eval
:
class << foo = Object.new
def bar(str)
puts "`self` inside `foo#bar` is #{self.inspect}"
binding.eval(str)
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
end
end
$this = self
foo.bar <<~'HERE'
puts "`self` inside the eval'd string is #{self.inspect}"
if $this.equal?(self)
puts "… which is the same as outside the eval'd string."
end
HERE
# `self` inside `foo#bar` is #<Object:0x0070070070070070>
# `self` inside the eval'd string is #<Object:0x0070070070070070>
self
- это один из трех неявных контекстов в Ruby:
self
- определитель по умолчанию
- постоянный контекст поиска
Есть хорошая статья в блоге yugui, в которой, в основном, говорится об определителе по умолчанию, но также кратко говорится о self
: Три неявных контекста в Ruby . Есть также более старая статья на японском языке, в которой есть немного больше деталей: Ruby