在Ruby中,我们如果需要调用module
的话可以使用extend
、include
、prepend
,但是这些关键字具体有哪些区别呢。
先创建一个Person
类,并且定义一个FooModule
模块
class Person
def introduce
puts "hello, i am from Person"
end
end
person = Person.new
person.introduce
#=> hello, i am from Person
module FooModule
def introduce
puts "hello, i am from Person FooModule"
end
def current_time
puts "current time is #{Time.now.to_s}"
end
end
extend
现在我们在Person
类中使用extend
关键字来调用模块,使用相关方法,并且打印出相关信息。
class Person
extend FooModule
end
Person.introduce
# => hello, i am from FooModule
person.introduce
# => hello, i am from Person
Person.current_time
# => current time is 2019-11-01 10:53:04 +0800
person.current_time
# => undefined method `current_time' for #<Person:0x000000028395d0> (NoMethodError)
我们由Person.introduce
和Person.current_time
可以观察出来extend
关键字的作用是为Person
添加了2个类方法。
include
class Person
include FooModule
end
Person.introduce
# => undefined method `introduce' for Person:Class (NoMethodError)
person.introduce
# => hello, i am from Person
Person.current_time
# => undefined method `current_time' for Person:Class (NoMethodError)
person.current_time
# => current time is 2019-11-01 10:59:28 +0800
上面两个类调用的方法都报错了可以看出,include
和extend
相反,include
是为类中添加的实例方法,而不是类方法。
prepend
prepend
和include
同样都是为类中添加实例方法,但不同之处在于,引入模块后的方法链会有一点区别
我们先看看 include
的方法链
class Person
# extend FooModule
include FooModule
# prepend FooModule
end
puts Person.ancestors
# =>Person
# =>FooModule
# =>Object
# =>JSON::Ext::Generator::GeneratorMethods::Object
# =>PP::ObjectMixin
# =>Kernel
# =>BasicObject
再看看prepend
的
class Person
# extend FooModule
# include FooModule
prepend FooModule
end
puts Person.ancestors
# =>FooModule
# =>Person
# =>Object
# =>JSON::Ext::Generator::GeneratorMethods::Object
# =>PP::ObjectMixin
# =>Kernel
# =>BasicObject
可以看出FooModule
和Person
的顺序有什么不同,那么具体不同体现在哪,接下来我们调用方法就可以看出区别了。
include
class Person
# extend FooModule
include FooModule
# prepend FooModule
end
person.introduce
# => hello, i am from Person
prepend
class Person
# extend FooModule
# include FooModule
prepend FooModule
end
person.introduce
# => hello, i am from FooModule
可以看到,如果使用prepend
的话我们会优先去查找FooModule
中的introduce
方法(如果FooModule
没有introduce
方法话,会依次去祖先链的上一级去查找introduce
方法),而include
是优先在Person
中去查找。
网友评论