ruby 如何解析 lambda 或块中的 `self` 关键字?
How does ruby resolve the `self` keyword in lambda or block?
就像JavaScript一样,在ruby中,lambda可以通过函数传递。
在JavaScript中this
将被解析为调用者对象。
但是 ruby 呢?同样的机制是否也适用于 ruby 的 lambda 或块?如何?你能给我一些示例代码吗?
顺便说一下,我已经阅读了 The Ruby Programming Language,但我无法从中找到任何有用的信息..
在 Ruby 中,self
是词法范围的,即 self
在块或 lambda 中是在同一位置而不在块或 lambda 中的任何内容。
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.
这也适用于 lambda:
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}
系列中的方法:
BasicObject#instance_exec
Module#module_exec
BasicObject#instance_eval
Module#module_eval
Class#module_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.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
这也适用于 lambda(转换为块):
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
object. You can then, in turn, evaluate code in the context of this specific binding using either the binding's Binding#eval
method or by passing the binding object to 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
:Three implicit contexts in Ruby. There is also an older article in Japanese which goes into a little more detail: Rubyの呼び出し可能オブジェクトの比較 (3) - なんかklassの話。
就像JavaScript一样,在ruby中,lambda可以通过函数传递。
在JavaScript中this
将被解析为调用者对象。
但是 ruby 呢?同样的机制是否也适用于 ruby 的 lambda 或块?如何?你能给我一些示例代码吗?
顺便说一下,我已经阅读了 The Ruby Programming Language,但我无法从中找到任何有用的信息..
在 Ruby 中,self
是词法范围的,即 self
在块或 lambda 中是在同一位置而不在块或 lambda 中的任何内容。
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.
这也适用于 lambda:
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}
系列中的方法:
BasicObject#instance_exec
Module#module_exec
BasicObject#instance_eval
Module#module_eval
Class#module_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.
# ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
这也适用于 lambda(转换为块):
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
object. You can then, in turn, evaluate code in the context of this specific binding using either the binding's Binding#eval
method or by passing the binding object to 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
:Three implicit contexts in Ruby. There is also an older article in Japanese which goes into a little more detail: Rubyの呼び出し可能オブジェクトの比較 (3) - なんかklassの話。