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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 04:51:30  来源:igfitidea点击:

Where and how is the _ (underscore) variable specified?

ruby

提问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.y1.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了我两个看似相关的结果:

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显然,从不存在的时代开始。