Ruby 在 module 定义时,使用 class << self 的目的是什么呢?

scuwolf · 2013年05月02日 · 最后由 smallX 回复于 2013年05月15日 · 13119 次阅读
module My_module
    def self.module_func
        puts 'self.module_func'
    end
    class << self
        def what_func
            puts 'what_func'
        end
    end
end

puts My_module.module_func
puts My_module.what_func

在 module 定义时,使用 class << sel f 的目的是什么呢?和 self.module_func 的区别又是什么

只是在有很多个self.的时候去用class << self,方便一些!

#2 楼 @tumayun

嗯,应该是这个原因,thx

再问一个问题,这种在一个 module 中定义 method_missing 为什么必须也要使用 class<<self 呢? 在《ruby 元编程》书中也没见过这种技术

module Facter 
....
  class << self
    # Allow users to call fact names directly on the Facter class,
    # either retrieving the value or comparing it to an existing value.
    def method_missing(name, *args)
      question = false
      if name.to_s =~ /\?$/
        question = true
        name = name.to_s.sub(/\?$/,'')
      end

      if fact = collection.fact(name)
        if question
          value = fact.value.downcase
          args.each do |arg|
            if arg.to_s.downcase == value
              return true
            end
          end

          # If we got this far, there was no match.
          return false
        else
          return fact.value
        end
      else
        # Else, fail like a normal missing method.
        raise NoMethodError, "Could not find fact '%s'" % name
      end
    end
  end
....
end

#2 楼 @tumayun 不只这点区别。

#5 楼 @zgm 多说几句。。。

@scuwolf

module M
  N = 1
end

class C
  include M

  def self.foo
    puts N
  end

  class << self
    def bar
      puts N
    end
  end
end

C.foo
C.bar

@zgm C.bar 报错;这是为什么呢?

#8 楼 @shin 所以我说不完全相通。

区别不止在于一点哪

#7 楼 @zgm 莫非又是作用域的问题?

#11 楼 @zgm 看元编程,可以找到你想要的

#13 楼 @smallX 你说点,或者 show 点代码,我手头上目前没这本书。

#8 楼 @shin

In a sense, the class keyword in Ruby is more like a scope operator than a class declaration. Yes, it does create classes that don’t yet exist, but you might argue that it does this as a side effect. For class, the core job is to move you in the context of the class, where you can define instance methods.

#16 楼 @fsword 除了 scope 与 context 的呢?我上面的例子中已经能够说明这点了。@smallX 说区别不止这点啊。

#8 楼 @shin 因为

class << C; ancestors; end  #====>   [Module, Object, PP::ObjectMixin, Kernel, BasicObject]

C 的 singleton_class 的 ancestors 中并不包含 M 这个 module, 找不到 N,所以会报错。

#17 楼 @zgm 我回错人了,其实就是解释一下你的代码, @smallX 说的我也不清楚,怀疑他也是看错了回复

#18 楼 @googya 这是现象,不是本质,本质是 @fsword 的 16 楼。

#14 楼 @zgm

class Demo
  class << self
    a = "aaaa"
    define_method :puts_a do
      puts a
    end
    def b
    end
  end
end

Demo.puts_a

#20 楼 @zgm @fsword 跟常量的查找机制相关吧

#21 楼 @smallX 没看懂撒。

有时这样的用法也挺有用的:

class  << self
  private
  def some_private_method
  end
end

#16 楼 @fsword @zgm

能否帮我解答下 #4 楼 的问题

#25 楼 @scuwolf 没人说必须啊。主要看你的 method_missing 想用在谁身上。

哦,我以前还没注意到这点,学习了!

@zgm @fsword 恩,还是有很多东西没有弄透彻,学习了

#7 楼 @zgm 好例子! 👍 琢磨了很久:

  1. "戴帽" :: 访问常量最好,M::N。
  2. 如常量 M::N 不变 😄 ,可以在 lnclude 后,新定义一个的同名常量。(见代码)。
module M
  N = 1
end

class C
  include M     #常量定义在 M中
  N = N         #C::N=M::N 
  def self.foo
    puts N
  end
  class << self
    def bar      
      puts N    #可以访问外层的常量C::N 了
    end
  end
end

C.foo   #=>1
C.bar   #=>1   ok
#------------------------------------------------
module M; N = 2; end    #改变M::N,  C中的C::N不变
C.foo   #=> 1           
C.bar   #=> 1

#7 楼 @zgm 借用一下你的例子

class C
  puts self
  class << self
    puts self
    def bar
       puts self
    end
    bar #在这里调用bar,会报错,找不到bar
  end
  bar
end

# 输出结果
C
#<Class:C>
C

从输出结果可以看到,class << self 这里,self 的作用域已经改变了,object_id 也变了,你可以自己输出来看看,参考 Class 类,当定义一个类的时候,an object of type Class is initialized and assigned to a global constant,可调用 constants 方法查看 self 包含的 constant。

这是 ruby 核心成员写的一篇文章 http://yugui.jp/articles/846

#30 楼 @zhenjunluo 和你说的 self 作用域什么的没有关系,定义方法的时候作用域和 self 也发生变化了,比如:

module M
  N = 1
end

class C
  include M
  def bar # 这里改变了作用域,也改变了self
    puts N
    puts self
  end
end

C.new.bar  => 
1
#<C:0x8906a20>

http://ruby-china.org/topics/4777 这篇帖子可能对你有帮助。

#30 楼 @zhenjunluo #31 楼 @zgm

class C
  self.send(:include,M)
  class << self
    self.send(:include,M)
    def bar
      puts N
    end
  end
end

这个怎么样? C::N #1 Class::N #1 常量并不属于 C new 出来的对象

#21 楼 @smallX 看不懂,求解释,这个例子能说明什么?除了 scope 和 context

#33 楼 @wisaly @zgm

class Foo
  class << self
    a = "aaaa"
    define_method :puts_a do
      puts a
    end
    def b
    end
  end
end

Foo.puts_a  #=> "aaaa"

class Bar
  a = "aaaa"
  class << self
    define_method :puts_a do
      puts a
    end
    def b
    end
  end
end

Bar.puts_a  #=> error

同样都是类方法访问,但是结果却不一样,就是说class << self 这种用法创建了新的 scope(作用域),而别的写法就不一定;在 ruby 的元编程中,self 是一个非常重要的概念。

下面这篇基本是必须阅读的一篇 blog 了,作者就不用说了 http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/

这是本坛里面的一个相关帖子,可以作辅助理解。 http://ruby-china.org/topics/1365

#33 楼 @wisaly ruby 里执行环境很重要的吧,任一处代码,是不是都有必要搞清楚的它的执行环境?

zputee Ruby 中的常量 提及了此话题。 04月03日 10:56
需要 登录 后方可回复, 如果你还没有账号请 注册新账号