简体   繁体   English

instance_eval 和 class << self?

[英]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; ExampleClass的实例,因此 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 << objself设置为给定块中的任何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 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 << objself设置为给定块中的任何obj ,在我的情况下是Class的实例,即Example (这可能是我错的地方);

No, class << obj opens up the singleton class of obj .不, class << obj打开objsingleton 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM