2009-11-08 99 views
5

这个问题有两个部分。扩展类和实例

在Ruby编程语言手册中,有一个使用模块扩展字符串对象和类的示例(第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 

回答

9

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

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

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

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

这是short answer

“Fixnums,符号,真实的,零和 假作为即时 值来实现。即日值, 变量保存对象本身, 而不是对它们的引用。

辛格尔顿方法不能定义为 这样的对象。相同的值的两个Fixnum总是表示相同的 对象实例,因此(例如) Fixnum的实例变量与 值“1”在所有之间共享这个“ones”就是这个系统。这使得 不可能定义一个单 方法只是其中之一。”

关过程中,您可以包括/ EXTEN的Fixnum对象类,每Fixnum对象实例会暴露在密新的方法。 这是正是Rails的/不的ActiveSupport为了让你写

3.days.ago 
1.hour.from_now 
+0

你回答第一部分没有解释(对我)的原因。在其他语言中,当您更改类并创建该类类型的新对象时,您将获得新方法。我假定从类到对象的连接是无效的。你能解释为什么这个连接在这里无效吗? – teleball 2009-11-08 18:00:31

+0

研究“包括”你给了我帮助。所以,现在看起来我明白扩展和包含之间存在差异,现在知道要搜索什么,这里有一篇文章解释了这些差异:http://stackoverflow.com/questions/156362/what-是最差之间-包括和 - 延长功能于红宝石 – teleball 2009-11-08 18:10:09

2

obj.extend(module)增加在module所有方法obj。当被称为String.extend(Greeter)你是从Greeter添加方法TH代表StringClass的实例。

将其他实例方法添加到现有类最简单的方法是重新打开该类。下面的例子做同样的事情:

class String 
    include Greeter 
end 

class String 
    def ciao 
    "Ciao!" 
    end 
end 

Fixnums(以及符号,真实,虚假,无)以不同的方式,以正常情况下的处理方式。具有相同值的两个Fixnum将始终由相同的对象实例表示。因此,Ruby不允许你扩展它们。

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

t = "Test" 
t.extend(Greeter) 
t.ciao 
=> "Ciao!"