问题描述
在两个类B
和C
中设置一个类变量@@foo
,其中两个类都不是另一个的子类,但它们都包含一个公共模块A
,似乎分别为B
和C
创建了@@foo
,其中A
无法访问:
Setting a class variable @@foo
in two classes B
and C
, where neither is a subclass of the other but they both include a common module A
, seems to create @@foo
separately for B
and C
, which A
cannot access:
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
/代码>.
But when @@foo
is assigned in A
, which works as an ancestor to both B
and C
, the @@foo
that B
and C
access becomes the @@foo
of A
.
module A; @@foo = 3 end
class B; p @@foo end # => 3
class C; p @@foo end # => 3
B
和 C
的 @@foo
发生了什么?当它的任何祖先的 @@foo
被分配时,它们是否被删除?
What happened to the @@foo
of B
and C
? Are they deleted when any of its ancestor's @@foo
is assigned?
推荐答案
此代码出现在 MRI 的 variable.c
和 rb_cvar_get
中的 rb_cvar_set
和 rb_cvar_get
>:
This code appears in both rb_cvar_set
and rb_cvar_get
in MRI's variable.c
:
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
是变量名 (@@foo
) 的 C 内部表示.
id
is the C-internal representation of the variable name (@@foo
).
front
是当前正在访问变量的类 (B
/C
).
target
是最远的祖先,其中变量也被定义过 (A
).
target
is the most distant ancestor in which the variable has also ever been defined (A
).
如果 front
和 target
不相同,Ruby 会警告 class 变量 #{id} of #{front}被#{target}
超越.
If front
and target
are not the same, Ruby warns that class variable #{id} of #{front} is overtaken by #{target}
.
然后从front
的RCLASS_IV_TBL 中逐字删除变量名称,以便在后续查找中,对该变量名称的搜索失败" 或 冒泡" 到定义变量的最远祖先.
The variable name is then literally deleted from front
's RCLASS_IV_TBL, so that on subsequent lookups, the search for that variable name "falls through" or "bubbles up" to the most distant ancestor in which the variable is defined.
请注意,此检查和删除操作不仅发生在 cvar 获取上,还发生在集合上:
Note that this check and deletion happen not just on cvar gets, but on sets as well:
$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
's 类变量被 A
取代!
In this example, even though it's A
's value of 3
being overwritten by the value 1
being set in B
, we still receive the same warning that it's B
's class variable being overtaken by A
!
虽然对于普通的 Ruby 程序员来说通常更令人惊讶的是发现他们的变量的值在各种可能出乎意料的地方(即在父母"/祖父母"/叔叔"/堂兄"/姐妹"模块和类),触发器和措辞都表明警告实际上是为了通知编码人员变量的真实来源"已更改.
While it is usually more surprising to the average Ruby coder to find that the value of their variable is changing in various, perhaps unexpected, places (i.e. in "parent"/"grandparent"/"uncle"/"cousin"/"sister" modules and classes), the trigger and the wording both indicate that the warning is actually intended to inform the coder that the variable's "source of truth" has changed.
这篇关于类变量的范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!