商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Ruby 中的 module

Ruby 中的 module

  发布于2026-06-29 阅读(0)

扫一扫,手机访问

在阅读开源 Ruby 代码或者编写可维护性代码时,经常会碰到 module_functionextend self 这两个东西。它们看起来有点像,但实际用起来差别不小。那么,它们到底有什么共同点,又有什么区别?别急,咱们一个一个拆开看。

Ruby 中的 module

module_function

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"

总结成两句话:

  • 方法会被复制到类的单例类中
  • 实例方法的可见性会变成 private

extend self

先回顾一下基础: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

本文转载于:https://www.jb51.net/article/114416.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

产品推荐

热门关注