4

在 Ruby 中,有几种方法可以声明一个类方法。

我们有这两种形式...

class Dog

  def self.species
    puts "I'm a dog."
  end

  def Dog.species_rly?
    puts "Still a dog."
  end

end

而这另一种更长的形式……

class Dog
  class << self
    def species_srsly?
      puts "OK, fine. I'm a cat."
    end
  end
end

为什么使用最后一种形式?有什么比这样做更好的呢?

class Dog
  def Dog.some_method
    # ...
  end
end
4

6 回答 6

3

这本精彩的书说这三种语法是相同的。选择哪一个是个人喜好问题。它还说def Dog.some_methodRuby 社区不赞成类名语法 ( )。我明白为什么:你在无缘无故地复制信息。如果您重命名您的类,您还必须更新所有方法定义。

因此,您可以在其余两种语法之间自由选择 :)

于 2012-04-15T21:20:11.953 回答
2

您会发现class << self只有在处理少量方法时表单才会更长。如果你要写,比如说,15 个类方法,突然间它变得清晰多了,重复性也少了很多。

归根结底,这是您使用的问题或个人风格。

于 2012-04-15T21:19:38.203 回答
1

绝对没有区别,这最终是一个偏好问题。有些人喜欢后者,因为它将所有“类”方法集中到一个块中,并且避免了必须写入self.每个方法定义。

前者使得每个方法在每个定义中都是显式的“类”方法这一事实。

我认为我永远不会使用Dog.some_method,因为它使重构比self.some_method.

于 2012-04-15T21:19:51.980 回答
1

技术上没有区别(至少我不知道)。

我避免

class Dog
  def Dog.species_rly?
    puts "Still a dog."
  end
end

如果我更改类名,我必须在每个方法定义中更改它。同样,如果我将一个方法从一个类复制到另一个类(如果这样做,请先考虑,是否应该定义一个模块并包含它)。

如果我有一种或两种方法,我会使用:

class Dog

  def self.species
    puts "I'm a dog."
  end

end

如果我有更多的类方法,那么我首先会想为什么。类方法通常只是不良设计的提示——也许您需要另一个(单例?)类。

如果我决定定义多个类方法,我会使用:

class Dog
  class << self
    def species_srsly?
      puts "OK, fine. I'm a cat."
    end
  end
end

有时我将源文件中的类方法分开,并将实例方法放在另一个源文件中。

于 2012-04-15T21:23:18.253 回答
1

class << self是最少重复的。def Dog.meth在全班重复“狗”,并def self.meth重复“自我”。

额外的缩进也可能是您在单例类方法而不是常规实例化方法中的视觉指示。

于 2012-04-15T21:44:56.947 回答
0

在 Dog 类中,self 是“Dog”类(每个类都有一个“类”对象,有时称为元类或特征类)。

以一种棘手的方式,ruby 中的所有方法都是实例方法。

def self.species

在“类类”上声明一个物种方法,这使得它(表现得像)一个类方法。

相似地,

d = Dog.new
def d.bark; puts "woof"; end

向“d”实例添加方法

至于两者的区别

class << self
  def species

def self.species

它们在功能上完成了同样的事情。正如其他人所提到的,选择一种格式而不是另一种格式是一种风格。def self.species 是声明“类”方法的常用方法。

我主要会使用

class << self
  attr_accessor :species
end

如果我想让属性访问器在类级别而不是实例上操作。

理解这一点对于使用像包含的模块这样的钩子很重要

module Sound
  def self.included(host_class)
    def host_class.speak(sound)
      define_method(:bark) do
        sound
      end
    end
  end
end
class Dog
  include Sound
  speak "woof"
end
Dog.new.bark

另外,为了完整性

class Dog
  def self.species
    puts self.to_s
  end
  def Dog.bark
    puts self.to_s
  end
end
class Spaniel < Dog; end

species 方法在任何子类的 self 上定义,而 :bark 方法总是在 Dog 上定义(除非被覆盖)

于 2012-04-16T12:43:38.737 回答