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
ing
idUScore
的源代码给了我两个看似相关的结果:

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] == '_';