Ruby 在何处以及如何指定(下划线)变量?
大多数人都知道,Ruby 在何处以及如何指定(下划线)变量?,ruby,Ruby,大多数人都知道,\uu作为最后返回值的持有者在IRB中的特殊意义,但这不是我在这里要问的 相反,我问的是当在普通的旧Ruby代码中用作变量名时的。在这里,它似乎有特殊的行为,类似于“不在乎变量”(a la)。以下是一些说明其独特行为的有用示例: lambda { |x, x| 42 } # SyntaxError: duplicated argument name lambda { |_, _| 42 }.call(4, 2) # => 42 lambda { |_,
\uu
作为最后返回值的持有者在IRB中的特殊意义,但这不是我在这里要问的
相反,我问的是当在普通的旧Ruby代码中用作变量名时的。在这里,它似乎有特殊的行为,类似于“不在乎变量”(a la)。以下是一些说明其独特行为的有用示例:
lambda { |x, x| 42 } # SyntaxError: duplicated argument name
lambda { |_, _| 42 }.call(4, 2) # => 42
lambda { |_, _| 42 }.call(_, _) # NameError: undefined local variable or method `_'
lambda { |_| _ + 1 }.call(42) # => 43
lambda { |_, _| _ }.call(4, 2) # 1.8.7: => 2
# 1.9.3: => 4
_ = 42
_ * 100 # => 4200
_, _ = 4, 2; _ # => 2
这些都是直接在Ruby中运行的(添加了put
s),而不是IRB,以避免与其附加功能冲突
不过,这都是我自己实验的结果,因为我在任何地方都找不到关于这种行为的任何文档(无可否认,这不是最容易搜索的东西)。最后,我很好奇所有这些在内部是如何工作的,这样我就可以更好地理解\uu
的特殊之处。因此,我要求参考文档,最好是Ruby源代码(也许还有),以揭示\uuu
在Ruby中的行为
注意:这大部分是由with引起的
是一个有效的标识符。标识符不能只包含下划线,还可以是下划线
_ = o = Object.new
_.object_id == o.object_id
# => true
也可以将其用作方法名称:
def o._; :_ end
o._
# => :_
当然,它并不完全是一个可读的名称,也不会向读者传递任何关于变量引用什么或方法执行什么的信息
IRB
,特别是将\uu
设置为最后一个表达式的值:
$ irb
> 'asd'
# => "asd"
> _
# => "asd"
实际上,它只是将\uu
设置为最后一个值:
@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
做了一些知识库探索。以下是我的发现:
在文件的最后几行,有一个调用:
REGISTER_SYMID(idUScore, "_");
grep
ingidUScore
的源代码给了我两个看似相关的结果:
- 在
- 在
shadowing\u lvar\u gen
似乎是块的形式参数替换另一个作用域中存在的同名变量的机制。函数似乎会引发“重复参数名”SyntaxError
和“隐藏外部局部变量”警告
在grep
对源代码进行shadowing\u lvar\u gen
之后,我发现了以下内容:
2007年12月11日星期二01:21:21松本幸弘
- parse.y(shadowing\u lvar\u gen)“\u”没有重复错误
这可能是以下原因的根源:
由此,我推断,在诸如proc{| | | | | |:x}.call:a,:b
这样的情况下,一个
变量只是将另一个变量隐藏起来
给你。它基本上介绍了这两条线:
if (!uscore) uscore = rb_intern("_");
if (uscore == name) return;
显然,从那时起,idUScore
甚至不存在。源代码中有一些特殊处理来抑制“重复参数名”错误。错误消息仅出现在parse.y
内的shadowing\u lvar\u gen
中:
而idUScore
是这样的:
REGISTER_SYMID(idUScore, "_");
您将在中看到类似的特殊处理:
并抑制以开头的变量的警告:
if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';
而不仅仅是本身。所以2.0稍微放松了一些。这根本不能解释为什么lambda{u124;},{u124; 42}
工作,而lambda{x,x{42}
不工作。@AndrewMarshall,看来你是对的<代码>| | |
确实有效,但| | | |
不起作用<代码>\uu
似乎有一些特殊的含义,我会看看是否可以从Ruby源代码中挖掘任何信息。顺便说一下,您的更新虽然信息丰富,但并不相关,因为它只适用于IRb,我在问题中明确指出了这一点,我没有问过。用于挖掘ChangeLog条目的+1。每个人都应该是C黑客:)+1的IRB源代码。IRB.CurrentContext.last_值非常值得了解,即使它与所提出的问题无关。我是在谷歌搜索IRB下划线的结果。我想知道1.8和1.9之间的调用(4,2)
的行为差异是否只是无意的副作用?在“正常”情况下,变量名不能重复,分配顺序无关紧要。@AndrewMarshall:是的,我认为“4 vs 2”问题只是1.8和1.9如何处理堆栈的产物。唯一值得注意的时间是| |,|,|,|
,因为重复错误已被抑制。@AndrewMarshall:我想知道是否每个人都在背后阅读彼此的更改日志。发现得好。我假设它会像这样简单,只是抑制双参数名称错误。Ruby真是一团糟:D@mu:当然,我还没有看到解释语言的真正干净的实现(Lua很接近)。
REGISTER_SYMID(idUScore, "_");
static void
warn_unused_var(struct parser_params *parser, struct local_vars *local)
{
/* ... */
for (i = 0; i < cnt; ++i) {
if (!v[i] || (u[i] & LVAR_USED)) continue;
if (idUScore == v[i]) continue;
rb_compile_warn(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
}
}
if (is_private_local_id(v[i])) continue;
rb_warn4S(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';