这个问题分为两部分。
在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
答案 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