在模块中使用 extend self
Using extend self in module
由于 question duplication 投票结束之前,我想说我的问题真的很简单(没有在上述问题中提出)。
有两个模块,一个定义了模块方法 using extend self
,另一个定义了mixin方法.
module A
extend self
def module_a_meth
"Called module_a_meth"
end
end
module B
def module_b_meth
"Called module_b_meth"
end
end
有一个class,其中我include
和extend
这些模块:
class Test
include A
extend A
include B
extend B
end
当我们 include
ing 模块时,它的方法变成 class' 实例方法,当 extend
ing - class 方法。
问题:
class,如果模块中的方法定义为 module 方法或 mixin 方法,对吧?我的意思是,当 include
d - 每个方法(模块方法或混合方法)变成 实例方法 ,当 extend
ed - 要么变成 class 方法.
如果我错了 - 区别在哪里?
obj = Test.new
puts obj.module_a_meth
puts obj.module_b_meth
puts Test.module_a_meth
puts Test.module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
编辑
请以是或否开始您的回答,因为我的问题暗示了这种类型的回答:)。
无论您使用的是 extend
还是 include
,您总是在复制实例方法。不同之处在于这些实例方法所在的位置。
当您调用 Class#include
时,您 "copying" 模块中的所有实例方法都是 class 中的实例方法。它类似于继承的工作方式,如果你调用 Class#ancestors
你会在那里看到模块。
当您调用 Object#extend
时,您正在将模块的所有实例方法复制到对象的单例 class。这是一个 class 只为这个在运行时创建的对象实例保留的。这就是您获得 "class methods" 的方式(例如 MyClass.hello_world
);通过将它们添加到 class 的单例中。您还可以做一些事情,比如扩展一个特定的对象实例(例如 s = String.new; s.extend(SomeModule); s.hello_world
)
还有其他一些差异。上下文绑定根据您使用的是 extend
还是 include
而不同。 extend
不会导致模块出现在祖先链中,而 include
会。
当尝试添加 "class" 和实例方法时,您会看到一种常见的模式是使用 included
回调来扩展基础 class一个 ClassMethods
模块:
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def hello_world
end
end
end
ActiveSupport::Concerns
还抽象了此模式,允许您在一次调用中添加实例和 "class" 方法。
我个人更喜欢让模块只与实例方法一起工作,并使用单例方法(例如 def self.my_method
)来使用作用域方法(有点像您使用私有方法的方式)。这允许消费者使用他们想要的 extend
或 include
并使其按预期工作。
我不确定这是否能回答您的问题,但有一些信息适合您
让我们分步看一下。
module A
puts "self = #{self}"
extend self
def module_a_meth
"Called module_a_meth"
end
end
class Test
end
Test.include A
#-> self = Test
Test.instance_methods.include?(:module_a_meth)
#=> true
Test.methods.include?(:module_a_meth)
#=> false - no class method
所以 include
包含 :module_a_meth
作为实例方法。由于 self
是 Test
,行:
extend self
相当于:
extend Test
这当然没有引用该模块。现在我们 extend
得到了预期的结果:
Test.extend A
#=> true
Test.methods.include?(:module_a_meth)
#=> true
including
和 extend
ing B
是正常的:
module B
def module_b_meth
"Called module_b_meth"
end
end
Test.include B
Test.instance_methods.include?(:module_b_meth)
#=> true
Test.extend B
Test.methods.include?(:module_b_meth)
#=> true
首先,关于实际问题:否 :).
Class(或任何其他对象)关心如何在您包含的模块中定义方法。基本上,您描述的模块中的方法被定义为 mixin
方法。 extend self
没有将方法重新定义为模块方法,但基本上将它们复制到两个上下文中。
extend
是如何工作的问题,这只是一个棘手的案例。
首先,将 extend
视为对象的单例 class 上下文中的 include
。这两个定义是相等的:
module SomeModule
def hi
'hi'
end
end
class SomeClass
extend SomeModule
end
class SomeClass
class << self
include SomeModule
end
end
鉴于此,通过在模块中使用 extend self
你是在说:采用我定义的所有混合方法并使用它们扩展模块的单例 class。这种魔法是 ruby 的本性的结果:重新打开任何定义的能力。下面是 extend self
的详细版本:
module Module1
def hi
'hi'
end
end
module Module1
extend Module1 # which is self
#### now "hi" is both here:
# def hi; end
#### and here:
# class << self; def hi; end
end
Module1.hi # => 'hi'
class SomeClass; include Module1; end;
SomeClass.new.hi # => 'hi'
__ 编辑 __
快速证明对象关心模块中的方法是如何定义的:
module SomeModule
def self.hi
'hi'
end
end
object = 'some string'
class << object
include SomeModule
end
object.hi # => NoMethodError: undefined method
由于 question duplication 投票结束之前,我想说我的问题真的很简单(没有在上述问题中提出)。
有两个模块,一个定义了模块方法 using extend self
,另一个定义了mixin方法.
module A
extend self
def module_a_meth
"Called module_a_meth"
end
end
module B
def module_b_meth
"Called module_b_meth"
end
end
有一个class,其中我include
和extend
这些模块:
class Test
include A
extend A
include B
extend B
end
当我们 include
ing 模块时,它的方法变成 class' 实例方法,当 extend
ing - class 方法。
问题:
class,如果模块中的方法定义为 module 方法或 mixin 方法,对吧?我的意思是,当 include
d - 每个方法(模块方法或混合方法)变成 实例方法 ,当 extend
ed - 要么变成 class 方法.
如果我错了 - 区别在哪里?
obj = Test.new
puts obj.module_a_meth
puts obj.module_b_meth
puts Test.module_a_meth
puts Test.module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
#=> Called module_a_meth
#=> Called module_b_meth
编辑
请以是或否开始您的回答,因为我的问题暗示了这种类型的回答:)。
无论您使用的是 extend
还是 include
,您总是在复制实例方法。不同之处在于这些实例方法所在的位置。
当您调用 Class#include
时,您 "copying" 模块中的所有实例方法都是 class 中的实例方法。它类似于继承的工作方式,如果你调用 Class#ancestors
你会在那里看到模块。
当您调用 Object#extend
时,您正在将模块的所有实例方法复制到对象的单例 class。这是一个 class 只为这个在运行时创建的对象实例保留的。这就是您获得 "class methods" 的方式(例如 MyClass.hello_world
);通过将它们添加到 class 的单例中。您还可以做一些事情,比如扩展一个特定的对象实例(例如 s = String.new; s.extend(SomeModule); s.hello_world
)
还有其他一些差异。上下文绑定根据您使用的是 extend
还是 include
而不同。 extend
不会导致模块出现在祖先链中,而 include
会。
当尝试添加 "class" 和实例方法时,您会看到一种常见的模式是使用 included
回调来扩展基础 class一个 ClassMethods
模块:
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def hello_world
end
end
end
ActiveSupport::Concerns
还抽象了此模式,允许您在一次调用中添加实例和 "class" 方法。
我个人更喜欢让模块只与实例方法一起工作,并使用单例方法(例如 def self.my_method
)来使用作用域方法(有点像您使用私有方法的方式)。这允许消费者使用他们想要的 extend
或 include
并使其按预期工作。
我不确定这是否能回答您的问题,但有一些信息适合您
让我们分步看一下。
module A
puts "self = #{self}"
extend self
def module_a_meth
"Called module_a_meth"
end
end
class Test
end
Test.include A
#-> self = Test
Test.instance_methods.include?(:module_a_meth)
#=> true
Test.methods.include?(:module_a_meth)
#=> false - no class method
所以 include
包含 :module_a_meth
作为实例方法。由于 self
是 Test
,行:
extend self
相当于:
extend Test
这当然没有引用该模块。现在我们 extend
得到了预期的结果:
Test.extend A
#=> true
Test.methods.include?(:module_a_meth)
#=> true
including
和 extend
ing B
是正常的:
module B
def module_b_meth
"Called module_b_meth"
end
end
Test.include B
Test.instance_methods.include?(:module_b_meth)
#=> true
Test.extend B
Test.methods.include?(:module_b_meth)
#=> true
首先,关于实际问题:否 :).
Class(或任何其他对象)关心如何在您包含的模块中定义方法。基本上,您描述的模块中的方法被定义为 mixin
方法。 extend self
没有将方法重新定义为模块方法,但基本上将它们复制到两个上下文中。
extend
是如何工作的问题,这只是一个棘手的案例。
首先,将 extend
视为对象的单例 class 上下文中的 include
。这两个定义是相等的:
module SomeModule
def hi
'hi'
end
end
class SomeClass
extend SomeModule
end
class SomeClass
class << self
include SomeModule
end
end
鉴于此,通过在模块中使用 extend self
你是在说:采用我定义的所有混合方法并使用它们扩展模块的单例 class。这种魔法是 ruby 的本性的结果:重新打开任何定义的能力。下面是 extend self
的详细版本:
module Module1
def hi
'hi'
end
end
module Module1
extend Module1 # which is self
#### now "hi" is both here:
# def hi; end
#### and here:
# class << self; def hi; end
end
Module1.hi # => 'hi'
class SomeClass; include Module1; end;
SomeClass.new.hi # => 'hi'
__ 编辑 __
快速证明对象关心模块中的方法是如何定义的:
module SomeModule
def self.hi
'hi'
end
end
object = 'some string'
class << object
include SomeModule
end
object.hi # => NoMethodError: undefined method