Ruby & RailsRuby on RailsRuby

module_function & extend sel

2017-04-30  本文已影响244人  老码农不上班

更多文章请访问独立博客 https://huangwenwei.com

在阅读开源的 Ruby 代码和编写可维护性的代码经常遇到这两者的使用,那么他们两者的共同点和区别是什么呢?

module_function

Ruby 的模块 (module) 是方法和常量的集合。模块中的方法又可分为实例方法和模块方法, 当一个模块被 include 到一个 Ruby 类时 ,模块中的方法(注:没有被 module_function 关键字标记的方法)就是类中的实例方法,需要所在的类被实例化之后才能被调用;被 module_function 关键字标记的方法称为模块方法 (module method),被标记之后模块中实例方法也会变成私有方法。调用模块方法的方式为:module_name.method_name,而在模块中没有被 module_function 关键字标记的方法不能这样被调用。

模块中的 module_function 关键字会把对应的方法编程模块方法且对于被 include 引入到所在的类来说不可见,所以不能被实例化对象调用。

如果要让模块方法也能以 module_name.method_name 的方式调用,可以考虑 extend self

# 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"

总结就是

extend self

Include is for adding methods to an instance of a class and extend is for adding class methods

extend 本质是给类或者模块添加类方法 。

extend self 让模块中的实例方法能够被 module_name.method_name 调用,同时保留模块中原方法的 public/private 属性,但又不像 module_function 一样把被标记的方法变成私有方法。

#!/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"

总结就是:

inheritances & extend & include 的区别

总结

module_function 改变模块内原方法的 public/private 属性并设置成模块方法,能够通过 module_name.method_name 的方法调用。

extend self 就是在模块内自继承,不改变模块中方法的 public/private 属性,同样也能通过 module_name.public_method 的方法调用。

另外,rubocop 推荐使用 module_function
Style/ModuleFunction: Use module_function instead of extend self. (https://github.com/bbatsov/ruby-style-guide#module-function)

参考链接
Self Improvement
Is “extend self” the same as “module_function”?
Include vs Extend in Ruby

上一篇下一篇

猜你喜欢

热点阅读