问题描述
大多数人都知道 _
在 IRB 中作为最后一个返回值的持有者的特殊含义,但这不是我在这里要问的.>
相反,我询问的是 _
在普通旧 Ruby 代码中用作变量名时的情况.这里它似乎有特殊的行为,类似于无关变量"(à la 序言).以下是一些说明其独特行为的有用示例:
lambda { |x, x|42 } # SyntaxError: 重复的参数名称拉姆达 { |_, _|42 }.call(4, 2) # =>42拉姆达 { |_, _|42 }.call(_, _) # NameError: 未定义的局部变量或方法`_'拉姆达 { |_|_ + 1 }.call(42) # =>43拉姆达 { |_, _|_ }.call(4, 2) # 1.8.7: =>2# 1.9.3: =>4_ = 42_ * 100 # =>4200_, _ = 4, 2;_ # =>2
这些都直接在 Ruby 中运行(添加了 puts
s)——而不是 IRB——以避免与其附加功能发生冲突.
不过,这都是我自己实验的结果,因为我在任何地方都找不到关于此行为的任何文档(诚然,这不是最容易搜索的东西).最后,我很好奇所有这些是如何在内部工作的,这样我才能更好地理解 _
的特别之处.所以我要求参考文档,最好是 Ruby 源代码(也许还有 RubySpec),它揭示了如何_
在 Ruby 中表现.
在源代码中有一些特殊处理来抑制重复参数名称"错误.错误消息仅出现在 parse.y
内的 shadowing_lvar_gen
中,1.9.3 版本看起来像这样:
静态IDshadowing_lvar_gen(struct parser_params *parser, ID name){if (idUScore == name) 返回名称;/* ... */
和 idUScore
是 在 id.c
像这样:
REGISTER_SYMID(idUScore, "_");
您将在 warn_unused_var
:
静态无效warn_unused_var(struct parser_params *parser, struct local_vars *local){/* ... */for (i = 0; i
您会注意到警告在
for
循环的第二行被抑制.
我在 1.9.3 源代码中可以找到的对
_
的唯一特殊处理是:重复名称错误被抑制,未使用的变量警告被抑制.除了这两件事,_
只是一个普通的旧变量.我不知道关于 _
的(次要)特殊性的任何文档.
在 Ruby 2.0 中, 被替换为对
is_private_local_id
的调用:
if (is_private_local_id(v[i])) continue;rb_warn4S(ruby_sourcefile, (int)u[i], "已分配但未使用的变量 - %s", rb_id2name(v[i]));
和
is_private_local_id
抑制以 _
开头的变量的警告:
if (name == idUScore) return 1;/* ... */返回 RSTRING_PTR(s)[0] == '_';
而不仅仅是
_
本身.所以 2.0 稍微放松了一些.
Most are aware of
_
’s special meaning in IRB as a holder for last return value, but that is not what I'm asking about here.
Instead, I’m asking about
_
when used as a variable name in plain-old-Ruby-code. Here it appears to have special behavior, akin to a "don't care variable" (à la Prolog). Here are some useful examples illustrating its unique behavior:
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
These were all run in Ruby directly (with
puts
s added in)—not IRB—to avoid conflicting with its additional functionality.
This is all a result of my own experimentation though, as I cannot find any documentation on this behavior anywhere (admittedly it's not the easiest thing to search for). Ultimately, I'm curious how all of this works internally so I can better understand exactly what is special about
_
. So I’m asking for references to documentation, and, preferably, the Ruby source code (and perhaps RubySpec) that reveal how _
behaves in Ruby.
解决方案
There is some special handling in the source to suppress the "duplicate argument name" error. The error message only appears in
shadowing_lvar_gen
inside parse.y
, the 1.9.3 version looks like this:
static ID
shadowing_lvar_gen(struct parser_params *parser, ID name)
{
if (idUScore == name) return name;
/* ... */
and
idUScore
is defined in id.c
like this:
REGISTER_SYMID(idUScore, "_");
You'll see similar special handling in
warn_unused_var
:
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]));
}
}
You'll notice that the warning is suppressed on the second line of the
for
loop.
The only special handling of
_
that I could find in the 1.9.3 source is above: the duplicate name error is suppressed and the unused variable warning is suppressed. Other than those two things, _
is just a plain old variable like any other. I don't know of any documentation about the (minor) specialness of _
.
In Ruby 2.0, the
idUScore == v[i]
test in warn_unused_var
is replaced with a call to is_private_local_id
:
if (is_private_local_id(v[i])) continue;
rb_warn4S(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
and
is_private_local_id
suppresses warnings for variables that begin with _
:
if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';
rather than just
_
itself. So 2.0 loosens things up a bit.
这篇关于_(下划线)变量在哪里以及如何指定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!