Getter/Setter 对于 Ruby 中的 class 个变量

Getter/Setter for class variables in Ruby

对于使用 attr_accessor:

为实例变量生成的 class 变量,getter/setter 是否可以 auto-generated/enabled
class School
  @@syllabus = :cbse

  def self.syllabus
    @@syllabus
  end

  def self.syllabus=(_)
    @@syllabus = _
  end
end

School.syllabus = :icse
School.syllabus # => :icse

您需要做的就是在 class 的范围内声明 attr_accessor:

class School
 class << self
   attr_accessor :syllabus
  end
end

School.syllabus = :icse
School.syllabus # => :icse

请注意,虽然基础成员 不会 @@syllabus(没有针对此类变量的内置解决方案),但 @syllabus class 范围,这是推荐的方式,请参阅 this 博客 post 了解两者之间的区别:

The issue with class variables is inheritance. Let’s say I want to subclass Polygon with Triangle like so:

class Triangle < Polygon
  @@sides = 3
end

puts Triangle.sides # => 3
puts Polygon.sides # => 3

Wha? But Polygon’s sides was set to 10? When you set a class variable, you set it for the superclass and all of the subclasses.

Uri Agassi 的回答是在 class 本身上设置实例变量,这与 class 变量类似但不同。有关差异的解释,请参阅 Difference between class variables and class instance variables?

您要查找的内容类似于 rails' cattr_accessor。您可以通过一些元编程来实现这一点

module CattrAccessors
  def cattr_accessor(*attrs)
    cattr_reader(*attrs)
    cattr_writer(*attrs)
  end

  def cattr_reader(*attrs)
    attrs.each do |attr|
      define_singleton_method(attr) { class_variable_get("@@#{attr}") }
    end
  end

  def cattr_writer(*attrs)
    attrs.each do |attr|
      define_singleton_method("#{attr}=") { |value| class_variable_set("@@#{attr}", value) }
    end
  end
end

然后像这样使用它:

class School
  extend CattrAccessors

  attr_accessor :syllabus
end

我没有测试过上面的模块,所以它可能不工作。如果没有,请告诉我。