Ruby里面extend include prepend 区别

2019-11-01  本文已影响0人  SSS_ruby

在Ruby中,我们如果需要调用module的话可以使用extendincludeprepend,但是这些关键字具体有哪些区别呢。

先创建一个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.introducePerson.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

上面两个类调用的方法都报错了可以看出,includeextend相反,include是为类中添加的实例方法,而不是类方法。

prepend

prependinclude同样都是为类中添加实例方法,但不同之处在于,引入模块后的方法链会有一点区别

我们先看看 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

可以看出FooModulePerson的顺序有什么不同,那么具体不同体现在哪,接下来我们调用方法就可以看出区别了。

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中去查找。

上一篇 下一篇

猜你喜欢

热点阅读