gpt4 book ai didi

ruby - 类变量的范围

转载 作者:数据小太阳 更新时间:2023-10-29 07:17:45 27 4
gpt4 key购买 nike

在两个类 BC 中设置一个类变量 @@foo,它们都不是另一个的子类,但它们都包含一个通用模块 A,似乎为 BC 创建了 @@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

但是当 @@foo 被分配给 A 时,它作为 BC 的祖先>,BC访问的@@foo成为A<的@@foo/.

module A; @@foo = 3 end
class B; p @@foo end # => 3
class C; p @@foo end # => 3

BC@@foo 发生了什么?当分配其祖先的任何 @@foo 时,它们是否被删除?

最佳答案

这段代码同时出现在 MRI 的 variable.c 中的 rb_cvar_setrb_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 是变量名 (@@foo) 的 C 内部表示。

front当前正在访问变量的类(B/C)。

target最远的祖先,其中变量也曾经被定义 (A)。

如果 fronttarget 不相同,Ruby 会警告 #{front} 的 class variable #{id}被#{target} 超越。

变量名随后从 front 的 RCLASS_IV_TBL 中逐字删除,因此在随后的查找中,对该变量名的搜索“落空”“冒泡” 到定义变量的最远祖先。


请注意,这种检查和删除不仅发生在 cvar gets 上,也发生在 set 上:

$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 取代!

虽然对于普通的 Ruby 编码人员来说,发现他们的变量的值在各种可能意想不到的地方发生变化通常会更令人惊讶(即在“ parent ”/“祖 parent ”/“叔叔”/“堂兄弟”/“姊妹”模块和类),触发器和措辞都表明警告实际上是为了通知编码员变量的“真实来源”已经改变。

关于ruby - 类变量的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21907938/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com