问题
class A
def set(v)
@@v = v
end
def put
puts @@v
end
end
class B < A
end
class C < A
end
B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c
Why? And how should I write this to have 'b' in last B.new.put?
回答1:
Here is a nice article on the subject - Class and Instance Variables In Ruby.
Basically, what you can do is:
class A
class << self
attr_accessor :class_var
end
def set_class_var(value)
self.class.class_var = value
end
def get_class_var
self.class.class_var
end
end
class B < A; end
A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b
A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb
To understand it you should think about A
as an instance of Class
class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:
a = A.new
def a.foo
puts 'foo'
end
In that case foo
is method defined only for a
object and not for every instance of A
class. And another way to define method in object's singleton class is like that:
class << a # open a's singleton class
def bar # define method that will be available only on 'a' object
puts 'bar'
end
end
In the first code snippet we use that approach to define class_var
attribute accessor in the context of singleton class of our A
class (it's a bit tricky, so you need to think about it). As the result class itself has class_var
variable as well as its descendant class B
. The difference is that every one of them has its own class_var
variable that do not interfere.
回答2:
Another option is to pull out class_inheritable_accessor code from Rails and include its behavior in your classes. See here for a good discussion and the guts of the code.
Perhaps you don't really want a class variable, though.
回答3:
Assigning a value to a class variable (an @@ variable) sets it for EVERY instance of the class. It even "sets" it for instances that "aren't created yet." So, consider this...
B.new.set 'b' # OK, that set @@v for that particular instance of B
B.new.put # Hey, you just created *another* new instance of B!
How can @@v have a value in that one? The second object's value of @@v would be unset, except for the fact that @@v is a class variable, so it has the same value for every instance of the class.
来源:https://stackoverflow.com/questions/8369050/ruby-and-class-variables-in-inherit-class