在哪里以及如何指定_(下划线)variables?

大多数人都知道IRB作为最后回报价值的持有者具有特殊的含义 ,但这不是我在这里问的。

相反,我在使用纯旧的Ruby代码作为variables名称时询问了_ 。 这里似乎有特殊的行为,类似于“无关variables”( à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 

这些都是在Ruby中直接运行的(join了puts ),而不是IRB,以避免与其他function冲突。

这是我自己实验的结果,尽pipe我无法在任何地方find有关这种行为的任何文档(当然,这不是search最简单的事情)。 最后,我很好奇所有这些在内部工作,所以我可以更好地理解_什么是特殊的。 所以我要求引用文档,最好是Ruby源代码(也可能是RubySpec ),它揭示了Ruby在Ruby中的行为。

注意:这大部分出现在与@Niklas B的 讨论中 。

源代码中有一些特殊的处理来抑制“重复的参数名称”错误。 该错误消息只出现在parse.y中的shadowing_lvar_gen , 1.9.3版本看起来像这样 :

 static ID shadowing_lvar_gen(struct parser_params *parser, ID name) { if (idUScore == name) return name; /* ... */ 

idUScoreid.c是这样定义的 :

 REGISTER_SYMID(idUScore, "_"); 

你会在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])); } } 

你会注意到在for循环的第二行中被禁止了。

我只能在1.9.3源代码中find_的唯一特殊处理:重复名称错误被抑制,未使用的variables警告被取消。 除了这两件事之外, _只是一个普通的旧variables。 我不知道关于_的(小)特殊性的任何文档。

在Ruby 2.0中, idUScore == v[i]testing被replace为对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])); 

is_private_local_id禁止以_开头的variables的警告

 if (name == idUScore) return 1; /* ... */ return RSTRING_PTR(s)[0] == '_'; 

而不仅仅是本身。 所以2.0放松了一下。

_是一个有效的标识符。 标识符不能只包含下划线,也可以是下划线。

 _ = o = Object.new _.object_id == o.object_id # => true 

您也可以将其用作方法名称:

 def o._; :_ end o._ # => :_ 

当然,这不是一个完全可读的名字,也不会向读者传递有关variables引用或方法的信息。

IRB特别将_设定为最后一个expression式的值:

 $ irb > 'asd' # => "asd" > _ # => "asd" 

就像在源代码中一样 ,它只是将_设置为最后一个值:

 @workspace.evaluate self, "_ = IRB.CurrentContext.last_value" 

有一些存储库的探索。 这是我发现的:

在文件id.c的最后一行,有这个调用:

 REGISTER_SYMID(idUScore, "_"); 

idUScore的源idUScore给了我两个看似相关的结果:

  • shadowing_lvar_gen函数中
  • warn_unused_var函数中

shadowing_lvar_gen似乎是块的forms参数replace另一个范围中存在的同名variables的机制。 似乎是引起“重复的参数名称” SyntaxError和“阴影外部局部variables”警告的函数。

grep shadowing_lvar_gen的源代码之后,我在Ruby 1.9.3的更新日志中发现了以下内容:

星期二十二月十一日01:21:21松本幸弘

  • parse.y(shadowing_lvar_gen):“_”没有重复的错误。

这可能是这一行的起源:

 if (idUScore == name) return name; 

由此我推断,在proc { |_, _| :x }.call :a, :b proc { |_, _| :x }.call :a, :b ,其中一个_variables只是影响另一个。


这是提交的问题 。 它基本上介绍了这两行:

 if (!uscore) uscore = rb_intern("_"); if (uscore == name) return; 

idUScore甚至不存在的时候,显然。