这段 Ruby 代码的作用是什么?:def self.metaclass; class << self; self; end; end

5
以下是来自Why's Poignant Guide to Ruby Chapter 6的Ruby代码片段,作者试图展示Ruby中的元编程:
# Get a metaclass for this class
def self.metaclass; class << self; self; end; end

我不太熟悉Ruby,但是这个展开后的形式是这样的吗?

def self.metaclass
    def self.self
    end
end

我理解的是这样。然而,我仍然不理解这段代码确切地做了什么。它的目的是什么?

在代码中进一步说明,为什么添加这个:

arr.each do |a|
   metaclass.instance_eval do
     define_method( a ) do |val|
       @traits ||= {}
       @traits[a] = val
     end
   end
 end

如果我理解正确的话,这段代码会将给定名称和值添加到@traits中。 是这样吗? 感谢您的帮助,以下是完整的源代码,可能对想要查看它的任何人都有帮助:
# The guts of life force within Dwemthy's Array
class Creature

# Get a metaclass for this class
def self.metaclass; class << self; self; end; end

# Advanced metaprogramming code for nice, clean traits
def self.traits( *arr )
 return @traits if arr.empty?

 # 1. Set up accessors for each variable
 attr_accessor *arr

 # 2. Add a new class method to for each trait.
 arr.each do |a|
   metaclass.instance_eval do
     define_method( a ) do |val|
       @traits ||= {}
       @traits[a] = val
     end
   end
 end

 # 3. For each monster, the `initialize' method
 #    should use the default number for each trait.
 class_eval do
   define_method( :initialize ) do
     self.class.traits.each do |k,v|
       instance_variable_set("@#{k}", v)
     end
   end
 end

end

# Creature attributes are read-only
traits :life, :strength, :charisma, :weapon
end

在使用中:

class Dragon < Creature
    life( 1340 )     # tough scales
    strength( 451 )  # bristling veins
    charisma( 1020 ) # toothy smile
    weapon( 939 )    # fire breath
end

3
阅读这篇文章:http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/本文深入讨论了 Ruby 中的元编程,特别是 self 关键字在元编程中的作用。阅读此文将有助于您更深入地理解 Ruby 语言中的元编程概念。 - Phrogz
谢谢,这似乎很有帮助。但我真的想了解def self.metaclass; class << self; self; end; end的含义。 - LonelyWebCrawler
2个回答

5
class Foo
  def self.bar    # Create a method invoked by Foo.bar instead of Foo.new.bar
    42            # the return value of this method (value of last expression)
  end
end


class Foo
  def self.jim    # Another method on the class itself
    class << self # Change the 'self' to be the metaclass of the current object
      self        # Evaluate the current 'self' as the 'return value' of 
    end           # class<<self…end; and since this is the last expression in
  end             # the method, its value is the return value for the method
end

简而言之,您看到的是 Creature 类本身(不是实例)定义了一个名为 metaclass 的方法。运行此方法时,它会查找 Creature 的元类并返回该元类。
在网上阅读有关对象的“元类”的内容,请点击此处:Read around the 'net

谢谢。我理解正确,使用#define_singleton_method已经不再必要了吗? - LonelyWebCrawler
2
如果你只想使用元类来定义一个方法,那么不需要。但是如果你想因为其他原因(例如列出所有的方法)访问元类,那么该方法就不够用了。然而,在1.9.2中引入的singleton_class方法可以执行相同的功能。 - Phrogz

2
“在展开形式下,它看起来完全相同:”
def self.metaclass
  class << self
    self
  end
end

注意它只返回self,因为它在元类的上下文中被评估,实际上是class << self所做的,self就是元类。
随着诸如define_singleton_method之类的东西的引入,需要直接访问元类的情况变得非常少。
这一切都非常复杂,似乎是“一切皆为对象”的设计原则的结果。

哇,你能否澄清一下那个以“注意这只是…”开头的段落? - LonelyWebCrawler
1
好的,内部块的内容就是 self,这将使它从该块中返回,因为没有执行其他语句。 - tadman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接