ruby。扩展所需的帮助

时间:2011-12-14 21:44:29

标签: ruby

给定的

module Foo
  def bar
    puts "foobar"
  end
end

我能做到

String.extend(Foo)

因此

String.bar # => "foobar"

为什么这不起作用?:

a = String.new
a.bar # => NoMethodError: undefined method `bar' for "":String

是因为'a'现在和实例和.extend仅对类方法有效吗?为什么它会失去我通过.extend给出String的'新'功能?

3 个答案:

答案 0 :(得分:6)

Ruby允许您以两种方式将模块中的方法添加到类中:extendinclude

使用您提供的模块:

module Foo
  def bar
    puts "foobar"
  end
end

使用extend方法将这些方法添加为类方法,并且可以直接在类对象本身上调用:

class Bar
  extend Foo
end

Bar.bar # => "foobar"

或者,您可以在类范围之外调用它:

class Bar
end

Bar.extend Foo

Bar.bar # => "foobar"

include略有不同。它会将方法添加为实例方法。它们只能在类的实例上调用:

class Bar
  include Foo
end

Bar.bar # NoMethodError
a = Bar.new
a.bar # => "foobar"

关键的区别在于,在我们调用实例方法之前,我们首先必须创建一个实例a

正如sepp2k所说,extend可以在任何Object上调用,而不仅仅是Class对象。例如,你可以去:

class Bar
end

a = Bar.new
a.extend Foo
a.bar # => "foobar"

但是,bar只会添加到单个实例a中。如果我们创建一个新实例,您将无法调用它。

b = Bar.new
b.bar # => MethodNotFoundError

答案 1 :(得分:0)

在Ruby中,类String是一个对象,通过执行String.extend(Foo),您可以为String类对象创建一个单例类,并在其中包含模块Foo(这意味着您要将类方法添加到字符串类对象,因此可以调用String.bar)。完全停止。

a.bar不起作用,因为没有实例方法栏。

不,你没有通过extend给String赋予新内容。

答案 2 :(得分:0)

Object#extend方法向接收者添加参数模块定义的方法。

你必须记住String类本身就是一个对象(类型为Class),因此当你用它作为接收者调用“extend”时,那个类对象(String)本身获取新方法。

因此,在您的第一个示例String.extend(Foo)中,将类实例添加到函数“bar”中。也就是说,“bar”现在是 shadow类(又名Singleton类)的实例方法,因此对象String(它是一个类)现在具有方法“bar”。这与将类方法添加到String类(例如def String.bar; puts 'foobar'; end)的效果大致相同,因此它对String类型的实例没有影响。