wangyile 2009-12-16 22:18
浏览 241
已采纳

Ruby中的单例方法

[code="ruby"]
class B
class<<self
def hello
puts "old"
end
end
end

class<<B
unless self.respond_to? :hello
def hello
puts "new"
end
end
end
B.hello
[/code]
[code="ruby"]
class B
class<<self
def hello
puts "old"
end
end
end

class<<B
unless B.respond_to? :hello
def hello
puts "new"
end
end
end
B.hello
[/code]

这两段代码大家可以运行下,第一段代码执行结果是new,而第二段代码执行结果是old 为什么呢?

  • 写回答

1条回答 默认 最新

  • rednaxelafx 2009-12-17 03:29
    关注

    因为class X; end中的“环境”是X这个类自身,而class << X; end中的“环境”是X的eigenclass,一个“虚拟类”。所以你会经常看到Ruby元编程的代码里有这种东西:
    [code="ruby"]class Object
    def eigenclass
    class << self
    self
    end
    end
    end[/code]
    这样可以获得一个对象的eigenclass。Ruby里类也是对象,而值对象是没有eigenclass的,所以会看到:
    [code="irb"]irb(main):001:0> class Object
    irb(main):002:1> def eigenclass
    irb(main):003:2> class << self; self; end
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> e = Object.eigenclass
    => #Class:Object
    irb(main):007:0> Object.is_a? Class
    => true
    irb(main):008:0> Object.is_a? e
    => true
    irb(main):009:0> 1.eigenclass
    TypeError: no virtual class for Fixnum
    from (irb):3:in `eigenclass'
    from (irb):9
    from :0[/code]
    楼主提的问题就在于,
    [code="ruby"]class B
    self
    end[/code]
    这里的self是指“B”类自己

    [code="ruby"]class B
    class << self # 1
    self # 2
    end
    end[/code]
    这里,1的self是“B”类自己,而2的self是B的eigenclass。

    [code="ruby"]class << B
    self
    end[/code]
    这里的self是B的eigenclass。

    [code="irb"]irb(main):001:0> class B
    irb(main):002:1> self
    irb(main):003:1> end
    => B
    irb(main):004:0> class << B
    irb(main):005:1> self
    irb(main):006:1> end
    => #Class:B[/code]

    [code="irb"]irb(main):001:0> class Object
    irb(main):002:1> def eigenclass
    irb(main):003:2> class << self; self; end
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> class B
    irb(main):007:1> def self.foo
    irb(main):008:2> 'foo'
    irb(main):009:2> end
    irb(main):010:1> class << self
    irb(main):011:2> def bar
    irb(main):012:3> 'bar'
    irb(main):013:3> end
    irb(main):014:2> end
    irb(main):015:1> end
    => nil
    irb(main):016:0> B.respond_to? :foo
    => true
    irb(main):017:0> B.respond_to? :bar
    => true
    irb(main):018:0> B.eigenclass.respond_to? :foo
    => false
    irb(main):019:0> B.eigenclass.respond_to? :bar
    => false
    irb(main):020:0> B.eigenclass.methods.grep /foo|bar/
    => []
    irb(main):021:0> B.eigenclass.instance_methods.grep /foo|bar/
    => ["bar", "foo"]
    irb(main):022:0> B.is_a? B.eigenclass
    => true[/code]
    可以看到foo和bar都成为了B的eigenclass的instance_methods,而不在其methods之中。

    在楼主给的代码中,由于B的eigenclass作为一个对象自己无法respond_to? :hello,而B作为B的eigenclass的实例则可以respond_to? :hello,所以就有楼主看到的行为了。

    引用Yugui画的一张图来展示Ruby 1.8里的类层次与实例的关系:[url=http://www.flickr.com/photos/yugui/3571683843/]Metaclass hierarchy 1.8[/url]
    (点击图左上角的all sizes)可以看到大图。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题