扩展类和实例

tel*_*all 5 ruby extension-methods

这个问题有两个部分.

在Ruby Programming Language一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节).

第一个问题.为什么如果使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?

irb(main):001:0> module Greeter; def ciao; "Ciao!"; end; end
=> nil
irb(main):002:0> String.extend(Greeter)
=> String
irb(main):003:0> String.ciao
=> "Ciao!"
irb(main):004:0> x = "foo bar"
=> "foo bar"
irb(main):005:0> x.ciao
NoMethodError: undefined method `ciao' for "foo bar":String
        from (irb):5
        from :0
irb(main):006:0>
Run Code Online (Sandbox Code Playgroud)

第二部分,当我尝试扩展Fixnum对象时,我得到一个未定义的方法错误.有人可以解释为什么这适用于字符串而不是fixnum?

irb(main):045:0> module Greeter; def ciao; "Ciao!"; end; end
=> nil
irb(main):006:0> 3.extend(Greeter)
TypeError: can't define singleton
        from (irb):6:in `extend_object'
        from (irb):6:in `extend'
        from (irb):6
Run Code Online (Sandbox Code Playgroud)

Sim*_*tti 9

第一个问题.为什么如果使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?

因为你扩展了String类,所以#ciao是一个类方法而不是实例方法.

String.send(:include, Greeter)
x = "foo bar"
x.ciao
# => "Ciao!"
Run Code Online (Sandbox Code Playgroud)

第二部分,当我尝试扩展Fixnum对象时,我得到一个未定义的方法错误.有人可以解释为什么这适用于字符串而不是fixnum?

这是简短的回答.

"Fixnums,Symbols,true,nil和false被实现为立即值.对于立即值,变量保存对象本身,而不是对它们的引用.

不能为这些对象定义单例方法.具有相同值的两个Fixnum总是表示相同的对象实例,因此(例如)Fixnum的实例变量与值"one"在所有"ones"之间共享是系统.这使得无法为其中一个定义单例方法."

当然,您可以包含/扩展Fixnum类,每个Fixnum实例都会公开Mixin中的方法.这正是Rails/ActiveSupport为了允许您编写而执行的操作

3.days.ago
1.hour.from_now
Run Code Online (Sandbox Code Playgroud)