ruby _(下划线)变量在哪里以及如何指定?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9559561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Where and how is the _ (underscore) variable specified?
提问by Andrew Marshall
Most are aware of _'s special meaning in IRB as a holder for last return value, but that is notwhat I'm asking about here.
大多数人都知道_'s 在 IRB 中作为最后一个返回值的持有者的特殊含义,但这不是我在这里要问的。
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:
相反,我问的是什么_时候用作普通 Ruby 代码中的变量名。在这里,它似乎具有特殊的行为,类似于“无关变量”(à la Prolog)。以下是一些说明其独特行为的有用示例:
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 putss added in)—not IRB—to avoid conflicting with its additional functionality.
这些都直接在 Ruby 中运行(puts添加了s)——而不是IRB——以避免与其附加功能发生冲突。
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.
不过,这都是我自己实验的结果,因为我在任何地方都找不到关于这种行为的任何文档(诚然,这不是最容易搜索的东西)。最终,我很好奇所有这些在内部是如何运作的,这样我才能更好地理解_. 所以我要求参考文档,最好是 Ruby 源代码(可能还有RubySpec),它揭示了_Ruby 中的行为。
Note: most of this arose out of this discussionwith @Niklas B.
注意:其中大部分来自与@Niklas B 的讨论。
采纳答案by mu is too short
There is some special handling in the source to suppress the "duplicate argument name" error. The error message only appears in shadowing_lvar_geninside parse.y, the 1.9.3 version looks like this:
源中有一些特殊处理来抑制“重复参数名称”错误。错误信息只出现在shadowing_lvar_geninside 中parse.y,1.9.3 版本如下所示:
static ID
shadowing_lvar_gen(struct parser_params *parser, ID name)
{
if (idUScore == name) return name;
/* ... */
and idUScoreis defined in id.clike this:
并且idUScore是在定义id.c这样的:
REGISTER_SYMID(idUScore, "_");
You'll see similar special handling in warn_unused_var:
你会在 中看到类似的特殊处理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 forloop.
您会注意到警告在for循环的第二行被抑制。
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 _.
_我可以在 1.9.3 源代码中找到的唯一特殊处理是:重复名称错误被抑制,未使用的变量警告被抑制。除了这两件事,_它只是一个普通的旧变量。我不知道关于_.
In Ruby 2.0, the idUScore == v[i]test in warn_unused_varis replaced with a call to is_private_local_id:
在 Ruby 2.0 中,idUScore == v[i]测试warn_unused_var被替换为调用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_idsuppresses warnings for variables that begin with _:
并is_private_local_id抑制以 开头的变量的警告_:
if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';
rather than just _itself. So 2.0 loosens things up a bit.
而不仅仅是_它自己。所以 2.0 稍微放松了一些。
回答by Matheus Moreira
_is a valid identifier. Identifiers can't just contain underscores, they can also bean underscore.
_是一个有效的标识符。标识符不能只包含下划线,它们也可以是下划线。
_ = o = Object.new
_.object_id == o.object_id
# => true
You can also use it as method names:
您还可以将其用作方法名称:
def o._; :_ end
o._
# => :_
Of course, it is not exactly a readable name, nor does it pass any information to the reader about what the variable refers to or what the method does.
当然,它并不是一个完全可读的名称,它也不会向读者传递任何关于变量所指的内容或方法的作用的信息。
IRB, in particular, sets _to the value of the last expression:
IRB,特别是,设置_为最后一个表达式的值:
$ irb
> 'asd'
# => "asd"
> _
# => "asd"
As it is in the source code, it simply sets _to the last value:
正如在源代码中一样,它只是设置_为最后一个值:
@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
Did some repository exploring. Here's what I found:
做了一些存储库探索。这是我发现的:
On the last lines of the file id.c, there is the call:
在文件的最后几行id.c,有这样的调用:
REGISTER_SYMID(idUScore, "_");
greping the source for idUScoregave me two seemingly relevant results:
greping 的来源给idUScore了我两个看似相关的结果:
- In the
shadowing_lvar_genfunction - In the
warn_unused_varfunction
shadowing_lvar_genseems to be the mechanism through which the formal parameter of a block replaces a variable of the same name that exists in another scope. It is the function that seems to raise "duplicated argument name" SyntaxErrorand the "shadowing outer local variable" warning.
shadowing_lvar_gen似乎是块的形式参数替换另一个作用域中存在的同名变量的机制。该函数似乎引发了“重复的参数名称”SyntaxError和“阴影外部局部变量”警告。
After greping the source for shadowing_lvar_gen, I found the following on the changelog for Ruby 1.9.3:
在greping 的源代码之后shadowing_lvar_gen,我在 Ruby 1.9.3 的更新日志中发现了以下内容:
Tue Dec 11 01:21:21 2007 Yukihiro Matsumoto
- parse.y (shadowing_lvar_gen): no duplicate error for "_".
2007 年 12 月 11 日星期二 01:21:21 松本幸弘
- parse.y (shadowing_lvar_gen):“_”没有重复错误。
Which is likely to be the origin of this line:
这很可能是这条线的起源:
if (idUScore == name) return name;
From this, I deduce that in a situation such as proc { |_, _| :x }.call :a, :b, one _variable simply shadows the other.
由此,我推断在诸如 的情况下proc { |_, _| :x }.call :a, :b,一个_变量只是简单地遮蔽了另一个变量。
Here's the commit in question. It basically introduced these two lines:
这是有问题的提交。它基本上介绍了这两行:
if (!uscore) uscore = rb_intern("_");
if (uscore == name) return;
From a time when idUScoredid not even exist, apparently.
idUScore显然,从不存在的时代开始。

