扩展类和实例

时间:2009-11-08 17:30:25

标签: 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>

第二部分,当我尝试扩展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

2 个答案:

答案 0 :(得分:9)

  

第一个问题。为什么如果你   使用新方法扩展一个类,和   然后创建一个对象/实例   class,你不能访问那个方法吗?

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

String.send(:include, Greeter)
x = "foo bar"
x.ciao
# => "Ciao!"
  

第二部分,当我尝试扩展一个   Fixnum对象,我得到一个未定义的   方法错误。有人可以解释原因   这适用于字符串但不适用于字符串   Fixnum对象?

这是short answer

  

“Fixnums,Symbols,true,nil,and   false实现为立即   值。立即价值观,   变量保存对象本身,   而不是引用它们。

     

无法定义单例方法   对于这样的对象。两个Fixnums   相同的值总是代表相同的   对象实例,所以(例如)   Fixnum的实例变量   值“一”在所有人之间共享   “那些”是系统。这使得   不可能定义单身人士   只针对其中一种的方法。“

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

所做的
3.days.ago
1.hour.from_now

答案 1 :(得分:2)

obj.extend(module)module中的所有方法添加到obj。当您调用String.extend(Greeter)时,您要将Greeter中的方法添加到代表Class的{​​{1}}实例。

向现有类添加其他实例方法的最简单方法是重新打开该类。以下示例执行相同的操作:

String

Fixnums(以及Symbols,true,false和nil)以与普通实例不同的方式处理。具有相同值的两个Fixnum将始终由同一对象实例表示。因此,Ruby不允许您扩展它们。

您当然可以扩展任何其他类的实例,例如:

class String
  include Greeter
end

class String
  def ciao
    "Ciao!"
  end
end