我只是花了很多时间在IRB
(好吧,PRY
实际上)试图弄清楚类变量在Ruby中是如何工作的,我完全被我发现的东西困惑了。
从我所见过的(如果我错了,请纠正我),类变量在类,这些类的实例,子类和子类实例之间共享。但是,对于子类及其实例,如果已在超类中分配了类变量,则只将类变量共享给超类。如果它还没有被分配到超类中,那么它在那里保持未定义,直到它被分配给变量变为共享的那一点......到底是什么? (如果您感到困惑,请参阅下面的示例。)
那为什么呢?我听说Ruby类变量基于Smalltalk中的一些类似概念,但我真的不知道为什么这种行为是可取的。
示例:
在superfoo_and_subbar.rb
:
class SuperFoo
def class_var_x=(x)
@@x = x
end
def class_var_x
@@x
end
end
class SubBar < SuperFoo
# Define these again, just in case they're bound at compile time or something...
def class_var_x=(x)
@@x = x
end
def class_var_x
@@x
end
end
在PRY
(或IRB
)会话中:
# Okay, let's do this!
require './superfoo_and_subbar' # => true
SuperFoo.new.class_var_x # NameError: uninitialized class variable @@x in SuperFoo
SubBar.new.class_var_x # NameError: uninitialized class variable @@x in SubBar
# Okay, no suprise there, let's define the class variable on SuperFoo
SuperFoo.new.class_var_x = 1
SuperFoo.new.class_var_x # => 1
# Okay, looks about right. What does bar say now?
SubBar.new.class_var_x # => 1
# Okay, that's pretty weird but I did hear that Ruby class variables behave
# that way, so no big deal.
SubBar.new.class_var_x = 2
SubBar.new.class_var_x # => 2
SuperFoo.new.class_var_x # => 2
# Right, so these both point to the same variable then.
新PRY会议:
# Now let's try this again:
require './superfoo_and_subbar' # => true
SuperFoo.new.class_var_x # NameError: uninitialized class variable @@x in SuperFoo
SubBar.new.class_var_x # NameError: uninitialized class variable @@x in SubBar
# So far so good. Let's set x on SubBar first this time
SubBar.new.class_var_x = 2
SubBar.new.class_var_x # => 2
# Okay, so x is now set on SubBar so it should also be set on SuperFoo then, right?
SuperFoo.new.class_var_x # NameError: uninitialized class variable @@x in SuperFoo
# Wait, what? So they're seperate variables now?
SubBar.new.class_var_x # => 2
SuperFoo.new.class_var_x # NameError: uninitialized class variable @@x in SuperFoo
# It certainly looks that way. What happens if I set x on SuperFoo then?
SuperFoo.new.class_var_x = 3
SuperFoo.new.class_var_x # => 3
SubBar.new.class_var_x # => 3
# Wait, so now they're the same varaible again? What the heck?
SubBar.new.class_var_x = 4
SuperFoo.new.class_var_x # => 4
SubBar.new.class_var_x # => 4
# ...WHY!?!? Seriously, what's the point of this?
答案 0 :(得分:2)
这就是继承的工作方式。是的类变量与其子类共享,一旦超类将定义它。 SubBar.new.class_var_x
仅在类SubBar
中创建了类变量。很明显,它的超类不会有任何访问权限。
class Foo
def x_class_var=(val)
@@x =val
end
def x_class_var
@@x
end
end
class Bar<Foo
def x_class_var=(val)
@@x =val
end
def x_class_var
@@x
end
end
Foo.class_variables # => []
Bar.class_variables # => []
Bar.new.x_class_var = 10
Foo.class_variables # => []
Bar.class_variables # => [:@@x]
Bar.new.x_class_var
在@@x
类中创建了类变量Bar
,而Foo
的超级类Bar
将无法访问此@@x
Foo.class_variables # => []
Bar.class_variables # => []
Foo.new.x_class_var = 10
Foo.class_variables # => [:@@x]
Bar.class_variables # => [:@@x]
1}}。现在看另一种方式 -
@@x
现在Foo
已在Foo
类中创建,因此作为Bar
的子类,@@x
可以访问{{1}}。这是因为类变量可以从超类到子类共享,而不是从子类到超类,如上例中所示。
答案 1 :(得分:1)
在第一个PRY会话中,当您选中SubBar.new.class_var_x
时,它会检查@@class_var_x
是否存在。由于它SuperFoo
和SubBar < SuperFoo
确实存在,因此SuperFoo
@@class_var_x
。
在第二个会话中,当您选中SuperFoo.new.class_var_x
时,没有查看SubBar
的{{1}},因为父类的对象不在关心从它们继承的类,因此它创建了@@class_var_x
的新实例。