使用Ruby的类<< self vs self.method:什么更好?

Mic*_*art 59 ruby

这个Ruby风格指南告诉我们更好地使用self.method_name而不是class method_name.但为什么?

class TestClass
  # bad
  class << self
    def first_method
      # body omitted
    end

    def second_method_etc
      # body omitted
    end
  end

  # good
  def self.first_method
    # body omitted
  end

  def self.second_method_etc
    # body omitted
  end
end
Run Code Online (Sandbox Code Playgroud)

有性能问题吗?

Gar*_*eth 89

class << self擅长将所有类方法保存在同一个块中.如果def self.method从那时起添加方法,则不能保证(除了约定和一厢情愿的想法)后面的文件中不会有额外的类方法.

def self.method擅长明确声明方法是一个类方法,而class << self你必须自己去找容器.

哪一个对您来说更重要是一个主观决定,还取决于其他人正在处理代码以及他们的偏好是什么.

  • 我不同意,这不仅仅是一个简单的个人选择.使用`<<`有一个代码可读性的缺点 - 请参阅@ Flexoid的答案.`class << self`语法和使用代码块的缺点是,如果块比几个方法更长,那么这些方法都不是类方法,除非你向上滚动到`class <<自我部分. (7认同)
  • 但这并不是“class &lt;&lt; self”特有的问题。我见过很多具有深层模块嵌套的源文件(更常见于大型、重要的项目),直到向上滚动一个方法所在的*类*时才清楚。 (2认同)

Chr*_*ris 29

通常,class << self在元编程中用于将类别设置为长时间的自我.如果我正在尝试编写10个方法,我会像这样使用它:

METHOD_APPENDICES = [1...10]
class << self
  METHOD_APPENDICES.each do |n|
    define_method("method#{n}") { n }
  end
end
Run Code Online (Sandbox Code Playgroud)

这将创建10个方法(method1,method2,method3等),只返回数字.class << self在这种情况下我会使用清晰度因为元编程self是至关重要的.self.在里面乱扔东西实际上会让事情变得不那么容易理解.

如果您只是正常地定义类方法,请坚持下去,self.class_method_name因为更多人可能会理解它.除非您希望观众理解它,否则无需引入元语法.


Jon*_*nor 24

如上所述,两种样式似乎都是等价的,但是使用class << self允许将类方法标记为privateprotected.例如:

class UsingDefSelf
  def self.a; 'public class method'; end
  private
  def self.b; 'public class method!'; end
end

class UsingSingletonClass
  class << self
    def a; 'public class method'; end
    private
    def b; 'private class method'; end
  end
end
Run Code Online (Sandbox Code Playgroud)

private只影响实例方法.使用单例类,我们定义该类的实例方法,它们变成包含类的类方法!

我们还可以标记类的方法是private使用def self:

class UsingDefSelf
  def self.a; 'private class method'; end
  def self.b; 'private class method!'; end
  private_class_method :a, :b
  # In Ruby 2.1 there is an alternative syntax
  private_class_method def self.c; 'private class method!'; end
end
Run Code Online (Sandbox Code Playgroud)

但我们不能将它们标记为protected,没有protected_class_method.(但是,由于class是其singletonclass的唯一实例,私有类方法和受保护的类方法几乎相同,只是它们的调用语法不同.)

此外,它比使用class << self标记private类方法更容易,因为您必须列出每个私有类方法定义中的所有方法名称private_class_method或前缀private_class_method.


Fle*_*oid 5

我认为他们认为self.*更好,因为你可以肯定地说,它是一个类或实例方法,而不必向上滚动和搜索这个class << self字符串.

  • 但是到那时,拥有私有方法是否会像“不可读”一样?因为它们都在“ private”关键字下缩进。我想在ruby中可以为每种方法显式调用“ private:method”,但是考虑到C语法的工作原理,我认为期望开发人员知道函数/方法定义可能包含上下文是不合理的。 (2认同)

non*_*arn 5

随便你。两者都很清楚您的工作。但是我想到了一些建议。

如果只定义一个类方法,请使用def self.xxx。因为仅定义一种方法,所以增加缩进级别可能会变得混乱。

如果要定义多个类方法,请使用class << self。因为写作def self.xxxdef self.yyy而且def self.zzz肯定是重复。为这些方法创建一个部分。

当类中的所有方法都是类方法时,可以使用modulewith module_function代替class。这使您可以定义仅使用的模块功能def xxx