Ruby中的类变量的Getter / Setter

Getter/Setter for class variables in Ruby

对于使用attr_accessor为实例变量生成的类变量,getter/setter是否可以自动生成/启用?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class School
  @@syllabus = :cbse

  def self.syllabus
    @@syllabus
  end

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

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


您需要做的只是在类的范围内声明attr_accessor

1
2
3
4
5
6
7
8
class School
 class << self
   attr_accessor :syllabus
  end
end

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

请注意,虽然底层成员不是@@syllabus(对于此类变量没有内置解决方案),但在类范围内,@syllabus是推荐的方法,但请参阅以下关于这两者的区别的博客文章:

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

1
2
3
4
5
6
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.


UriAgassi的答案是在类本身上设置实例变量,类似于类变量,但与类变量不同。看到类变量和类实例变量之间的区别了吗?为了解释这些差异。

你要找的是像Rails的cattr_accessor一样的东西。你可以通过一点元编程来实现这一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

然后像这样使用:

1
2
3
4
5
class School
  extend CattrAccessors

  attr_accessor :syllabus
end

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