您可以调用include来将模块与ruby中的类混合,但必须在类定义的开头进行。为什么不能在类函数内完成?是否有替代语法?
EX:
module UsefulThings
def a() puts "a" end
end
class IncludeTester
include UsefulThings
def initialize
end
end
n = IncludeTester.new
n.a()
^^这样可行,但如果我将IncludeTester更改为以下内容,则会收到错误“undefined method`include'”
class IncludeTester
def initialize
include UsefulThings
end
end
答案 0 :(得分:6)
可以在类方法中完成。
这有效:
module UsefulThings
def a
puts "a"
end
end
class IncludeTester
def self.mix_in_useful_things
include UsefulThings
end
end
x = IncludeTester.new
IncludeTester.mix_in_useful_things
x.a # => a
但“initialize”不是类方法,而是实例方法。
“new”是一种类方法。您可以将new视为分配新对象,然后对其进行初始化,将初始化的参数传递给new。
你不能直接在initialize中调用include,因为include是Class的私有方法(继承自Module),而不是新创建的IncludeTester实例。
如果要将模块包含在实例方法的类中,则必须执行以下操作:
class IncludeTester
def initialize
self.class.send(:include, UsefulThings)
end
end
这里有必要使用“send”,因为include是私有方法,这意味着它只能用隐式接收器(self)直接调用。
当你在类定义中正常调用initialize时,你实际上是用一个隐含的“self”接收器来调用它,指的是被定义的类。
这是执行此操作时实际发生的情况:
class IncludeTester
include UsefulThings
end
答案 1 :(得分:4)
include
是Module的一个方法,Module是Class的超类,因此include
是Class上的一个方法,它使它成为IncludeTester中的一个类方法。当你这样做时:
class IncludeTester
def initialize
include UsefulThings
end
end
你试图在实例方法中调用类方法而Ruby说
`initialize':未定义的方法`include'
因为没有名为include
的实例方法。如果要在实例方法(例如initialize
)中调用类方法,则执行以下操作:
def initialize
self.class.include UsefulThings
end
但这不起作用,因为include
是私有方法;你可以用class_eval
解决这个问题:
def initialize
self.class.class_eval {
include UsefulThings
}
end
每次实例化include UsefulThings
时,您都会执行IncludeTester
,除了没有多大意义之外,如果UsefulThings
有included
方法,则可能会导致问题。
答案 2 :(得分:2)
实际上完全可以从类方法中包含一个模块,如下所示:
module Stuff
def say_hello
puts "hello"
end
end
class Foo
def self.i_am_a_class_method
include Stuff
end
def i_am_an_instance_method
end
end
但是,您无法从实例方法执行此操作,因为include method仅可用作私有类方法,因此无法从Foo.new实例访问。
答案 3 :(得分:0)
您需要extend
方法:
class IncludeTester
def initialize
extend UsefulThings
end
end
这不需要在方法中完成:
IncludeTester.new.tap { |newTester| newTester.extend(UsefulThings) }