发布于2026-06-29 阅读(0)
扫一扫,手机访问
在阅读开源 Ruby 代码或者编写可维护性代码时,经常会碰到 module_function 和 extend self 这两个东西。它们看起来有点像,但实际用起来差别不小。那么,它们到底有什么共同点,又有什么区别?别急,咱们一个一个拆开看。

Ruby 的 module 本质上是方法和常量的集合。module 里的方法又分为 instance method 和 module method。当一个 module 被 include 进一个 class 时,module 中那些没有被 module_function 标记的方法就会成为 class 的实例方法——也就是说,需要先把 class 实例化,然后才能通过对象调用。
一旦某个方法被 module_function 标记,不管它原来是被声明为 public 还是 private,它都会变成 module method,并且原来的实例方法会被改成 private。对于包含这个 module 的 class 来说,这个被标记的方法就成了私有实例方法,所以用 对象.module_method 的方式会报错。而 module method 则可以通过 模块名.方法名 直接调用。没有被 module_function 标记的 public 方法,则不能用模块名直接调用。
简单来说:module_function 把模块里的方法复制到模块的单例类中,同时将原来的实例方法设为 private。
看一段代码应该会更清楚:
# test.rb module MyModule def public_meth p "a public method, if the module is included to a class , can be call as object.public_meth" end def module_method p "a module method,can be called as module_name.module_method. but can not be call as object.module_method" end private def private_method_to_module_function p "a private_method, but can be call as module_name.module_method, because it was assigned to module_function" end def private_method p "I am a private method" end module_function :module_method, :private_method_to_module_function end MyModule.module_method MyModule.private_method_to_module_function begin MyModule.public_meth rescue p "public method can not be called by module_name.public_meth" end begin MyModule.private_method rescue NoMethodError p "private method can not be called by module_name.module_method" end class MyClass include MyModule end obj = MyClass.new obj.public_meth begin obj.private_method rescue NoMethodError p "private method in module can not be call by object.method_name" end begin obj.module_method rescue NoMethodError p "module method can not be called by object.method_name, for object, module method is private instance method" end #调用 ruby test.rb "a module method,can be called as module_name.module_method. but can not be call as object.module_method" "a private_method, but can be call as module_name.module_method, because it was assigned to module_function" "public method can not be called by module_name.public_meth" "private method can not be called by module_name.module_method" "a public method, if the module is included to a class , can be call as object.public_meth" "private method in module can not be call by object.method_name" "module method can not be called by object.method_name, for object, module method is private instance method"
总结成两句话:
先回顾一下基础:include 是给类的实例添加实例方法,而 extend 是给类或模块添加类方法(也就是单例方法)。
那 extend self 是干什么的呢?它让 module 中的实例方法能够通过 模块名.方法名 直接调用,同时保留方法原有的 public 或 private 属性。不像 module_function 那样会把被标记的方法强制变成 private,extend self 不会改变方法的可见性。
换句话说,extend self 就是在模块内部自己扩展自己,相当于把模块本身当作一个对象,把它自己的实例方法变成它自己的单例方法。
再来看代码:
#!/usr/bin/env ruby # encoding: utf-8 # test_extend.rb module MyModule extend self def public_meth p "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" private_method end private def private_method p "a private method, can be call in module internal" end end class MyClass include MyModule end MyModule.public_meth begin MyModule.private_method rescue NoMethodError p "private method in extend self module can not be called module_name.private_method" end obj = MyClass.new obj.public_meth begin obj.private_method rescue NoMethodError p "private method can not be called by object.private_method" end # 调用 ruby test_extend.rb "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" "a private method, can be call in module internal" "private method in extend self module can not be called module_name.private_method" "a public_method extended by self can be called by module_name.public_meth and object.public_meth, included by a class" "a private method, can be call in module internal" "private method can not be called by object.private_method"
这里的总结也很清晰:
module_function 会改变模块内方法原有的 public/private 属性,把方法变成 module method,同时原来的实例方法被设成 private。因此,只有被标记的方法才能通过 模块名.方法名 调用,而未被标记的 public 方法只能通过包含该模块的类的实例来调用。
extend self 则是在模块内部做了一次自引用,不会改变方法的可见性,所以模块里的 public 方法既能通过 模块名.方法名 调用,也能通过类的实例调用(因为 include 后仍为实例方法)。private 方法则只能在模块内部使用,外部无论通过模块名还是对象都无法访问。
两者的选择完全取决于你希望对外暴露什么样的接口:如果想让某些方法同时支持模块级调用和实例级调用,并且不破坏原有可见性,extend self 更合适;如果想把一部分方法“升级”成模块方法,同时让原来的实例方法变成私有,那就用 module_function。
上一篇:Ruby是什么以及如何使用
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8