[英]Difference between instance_eval and class << self?
I can't seem to grasp the exact difference between these two "constructs".我似乎无法掌握这两个“构造”之间的确切区别。 To my mind, the following small script should output the same thing three times:在我看来,下面的小脚本应该 output 相同的东西 3 次:
class Example
puts self
class << self
puts self
end
instance_eval do
puts self
end
end
However, the output is:但是,output 是:
Example
#<Class:Example>
Example
Here's my rationale:这是我的理由:
Example
is an instance of Class
, so self
in the class body refers to that; Example
是Class
的实例,因此 class 正文中的self
指的是那个;class << obj
sets self
to whatever obj
is in the given block, which in my case is the instance of Class
that is Example
(this is where I'm probably wrong); class << obj
将self
设置为给定块中的任何obj
,在我的情况下是Class
的实例,即Example
(这可能是我错的地方);instance_eval
runs the block in the given instance, so, in my case it's pretty much the same as putting the code in the block directly in the class body. instance_eval
在给定实例中运行该块,因此,在我的情况下,它与将代码直接放在 class 主体中的块中几乎相同。 My current guess is that class << self
inserts a ghost class between Example
and Class
and sets self to that, but the output of #<Class:Example>
is not confirming that at all. My current guess is that class << self
inserts a ghost class between Example
and Class
and sets self to that, but the output of #<Class:Example>
is not confirming that at all.
So what is wrong with my rationale?那么我的理由有什么问题呢?
class << obj
setsself
to whateverobj
is in the given block, which in my case is the instance ofClass
that isExample
(this is where I'm probably wrong);class << obj
将self
设置为给定块中的任何obj
,在我的情况下是Class
的实例,即Example
(这可能是我错的地方);
No, class << obj
opens up the singleton class of obj
.不, class << obj
打开obj
的singleton class 。 As you correctly pointed out, inside of a class declaration, self
refers to the class itself, so, in this case, the "inner" self
(ie the one being passed to puts
) refers to the singleton class of Example
. As you correctly pointed out, inside of a class declaration, self
refers to the class itself, so, in this case, the "inner" self
(ie the one being passed to puts
) refers to the singleton class of Example
.
In my opinion, class << self
has been one of the most obnoxious bits of syntax in Ruby.在我看来, class << self
一直是 Ruby 中最令人讨厌的语法位之一。 People new to the language have little idea what it means, apart from cargo-cult conventions, and even those intimately familiar with the language have only a hazy understanding of what differentiates it from instance_method
, as the two do seem to be remarkably similar.刚接触该语言的人几乎不知道它的含义,除了货物崇拜约定,即使是那些非常熟悉该语言的人也对它与instance_method
的区别只有模糊的理解,因为两者似乎非常相似。
Here's an example of two different ways of defining a class method:下面是定义 class 方法的两种不同方法的示例:
class Example
class << self
def class_def
:class_def
end
end
instance_eval do
def instance_def
:instance_def
end
end
end
You can check that these work by calling the methods:您可以通过调用以下方法来检查这些是否有效:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => :instance_def
The difference is when you're dynamically creating methods using define_method
since the binding does appear to be incorrect on the instance_eval
version:不同之处在于当您使用define_method
动态创建方法时,因为在instance_eval
版本上绑定似乎不正确:
class Example
class << self
define_method(:class_def) do
:class_def
end
end
instance_eval do
define_method(:instance_def) do
:instance_def
end
end
end
This results in the instance_def
method being defined, but not being bound to the class itself:这导致instance_def
方法被定义,但没有绑定到 class 本身:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => NoMethodError: undefined method ‘instance_def’ for Example:Class
The only reliable way to create dynamic methods is with class << self
.创建动态方法的唯一可靠方法是使用class << self
。 The method instance_def
appears to be created and discarded as it doesn't show up in Example.methods even inside that block.方法instance_def
似乎被创建和丢弃,因为即使在该块内它也没有出现在 Example.methods 中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.