ruby – 类变量的范围
在两个B和C类中设置一个类变量@@ foo,其中两个类都不是另一个的子类,但它们都包含一个公共模块A,似乎分别为B和C创建@@ foo,A无法访问:
module A; end class B; include A; @@foo = 1 end class C; include A; @@foo = 2 end module A; p @@foo end # => NameError: uninitialized class variable @@foo in A class B; p @@foo end # => 1 class C; p @@foo end # => 2 但是,如果在A中分配@@ foo,它作为B和C的祖先,那么B和C访问的@@ foo成为A的@@ foo. module A; @@foo = 3 end class B; p @@foo end # => 3 class C; p @@foo end # => 3 B和C的@@ foo怎么了?当它的任何祖先的@@ foo被分配时它们是否被删除? 解决方法
此代码出现在MRI的variable.c中的rb_cvar_set和rb_cvar_get中:
if (front && target != front) { st_data_t did = id; if (RTEST(ruby_verbose)) { rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",QUOTE_ID(id),rb_class_name(original_module(front)),rb_class_name(original_module(target))); } if (BUILTIN_TYPE(front) == T_CLASS) { st_delete(RCLASS_IV_TBL(front),&did,0); } } id是变量名的C内部表示(@@ foo). front是当前正在访问变量的类(B / C). target是最远的祖先,变量也曾被定义过(A). 如果front和target不相同,Ruby会警告#{front}的类变量#{id}被#{target}超越. 然后从前面的RCLASS_IV_TBL中逐字删除变量名,以便在后续查找中,搜索该变量名称“通过”或“冒泡”到定义变量的最远祖先. 请注意,此检查和删除不仅发生在cvar gets上,还发生在集合上: $VERBOSE = true module A; end class B; include A; @@foo = 1; end # => 1 module A; @@foo = 3 end # => 3 class B; p @@foo = 1 end # => 1 #=> warning: class variable @@foo of B is overtaken by A module A; p @@foo end # => 1 在这个例子中,即使A的值3被B中设置的值1覆盖,我们仍然会收到相同的警告:B的类变量被A超越! 虽然普通的Ruby编码器通常会发现他们的变量值在各种各样的,也许是意想不到的地方(即“父母”/“祖父母”/“叔叔”/“堂兄”/“姐妹”)发生变化,这一点更令人惊讶模块和类),触发器和措辞都表明警告实际上是为了通知编码人变量的“真实来源”已经改变. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |