Ruby Ruby 的常量查找路径问题

vincent · 2012年08月07日 · 最后由 xiaoronglv 回复于 2014年06月29日 · 6040 次阅读

最近遇到一个问题,百思不得解,那位兄弟可以解析一下。 看一下下面的代码

module M1
  CT = "ok"
end

class C1
  CK = "ck"
  include M1

  def self.method1
    puts self
    puts "#{CK} in method1"
    puts "#{CT} in method1"
  end

  class << self    
    def method2
      puts self
      puts "#{CK} in method1"
      puts "#{CT} in method2"
    end
  end
end

C1.method1
C1.method2 

输出结果是

C1
ck in method1
ok in method1
C1
ck in method2
NameError: uninitialized constant Class::CT
    from (irb):16:in `method2'

method1 和 method2 都是常见的类方法的定义方面,我向来认为它们是等价可替换的写法,但是从实际执行的结果看,它们里面的常量查找路径不一样,谁能解析一下?

binding 不一样,第一个在 C1 中,第二个在 C1 的 singletonclass 中

如果我把 M1 的定义改成下面的样子:

module M1
  def self.included(base)
    base.extend(self)
  end
  CT = "ok"
end

执行结果

C1
ck in method1
ok in method1
C1
ck in method2
ok in method2

#2 楼 @vincent 第二种写法复制了两个 CT,一个在 C1 中,一个在 C1 的 singletion class 中,所以怎么写都能访问到。 你第一种写法,1 楼已回答了,主要是上下文的问题。

class << self    
   def method2
     puts self
     puts "#{CK} in method1"
     puts "#{self::CT} in method2"
   end
 end


优雅的写法:


module M1
   CT = "ok"
end

class C1
   CK = "ck"
   include M1

   def self.method1
      puts self
      puts "#{CK} in method1"
      puts "#{CT} in method1"
   end
end

class C1
   def self.method2
      puts self
      puts "#{CK} in method1"
      puts "#{CT} in method2"
   end
end
C1.method1
C1.method2

#7 楼 @sevk

有必要用 class << self 的写法,因为可以限制类方法的可见范围,比如

class C1
  class << self
     def method3
       ...
     end

     private

     def method4
       ...
     end
  end
end
C1.method4
>> NoMethodError: private method `method4' called for C1:Class

还可以在 C1 中使用 extend M1

class C1
  extend M1
.
.
.
end

输出

C1
ck in method1
ok in method1
C1
ck in method2
ok in method2

#8 楼 @vincent 我不明白这种定义类方法的形式和传统的相比执行速度有没有影响?

#10 楼 @simonykq 两种定义方法 method 的查找路径有些差异,但是性能应该不会有多少差别。

#4 楼 @vincent

看了两遍,懂了一点点,还有一点疑问。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号