Ruby里面extend include prepend 区别

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,142评论 1 32
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,858评论 2 9
  • Ruby是一门单一继承的面向对象语言,那么在内部结构上,它是以object为根节点的树形结构的类图,那么我们在Ru...
    falm阅读 1,450评论 0 1
  • 读书的时候,我的生日基本在期末考试附近,所以也没什么心思过生日,渐渐地就不习惯过生日了。今天恍然,天呐,25岁啦,...
    Dorisxtly阅读 291评论 0 0
  • 天刚微微亮,她难得的早醒了一回。身边的胖娃还在酣睡,小嘴微微张开,小腿儿不老实的伸出了被子外,长长的睫毛让一张小脸...
    心有欢喜过生活阅读 465评论 6 5