4

我已经按照 Why's (Poignant) Guide to Ruby,通过其他几个指南,到Ruby 风格指南来了解 Rubyists 的想法。但这是我第一次看到尾随下划线。这些是什么东西?它们有用吗?如果有用,我们何时使用它们以及如何将它们与 splat 运算符一起使用?

(Ruby 样式指南链接锚定到实际示例)

4

2 回答 2

8

合法的变量名是_. 类似的东西*_类似于*x. 尾随下划线变量一词实际上是指赋值语句左侧以逗号分隔的一系列变量中的最后一个变量名称,例如:

a, b, _ = [1, 2, 3, 4]

splat 运算符有两种用途:

  1. 将一个数组分解成它的单个项目。
  2. 将项目收集到一个数组中。

发生哪种情况取决于使用 splat 运算符 的上下文。

以下是 Ruby 风格指南所说的不好的示例:

a, b, _ = *foo

该示例中的尾随下划线变量是不必要的,因为您可以将 的前两个元素分配给foo变量ab编写:

a, b = *foo

下划线变量用来表示,我不关心这个变量,因此如果你想做的只是分配给a和,那么在那个例子中没有必要b

该示例也可能被认为是不好的样式,因为*也不需要运算符(来源:Cary Swoveland):

a, b = [1, 2, 3]
p a, b

--output:--
1
2

* 可以在右侧使用,效果如下:

x, y, z = 10, [20, 30]
p x, y, z

--output:--
10
[20, 30]
nil

x, y, z = 10, *[20, 30]
p x, y, z

--output:--
10
20
30

因此,请记住,在样式指南的其余示例中*,右侧是多余的。

下一个不好的例子是:

a, _, _ = *foo

这是一个更具体的例子:

a, _, _ = *[1, 2, 3, 4]
p a, _

puts "-" * 10

a, _ = *[1, 2, 3, 4]
p a, _

--output:--
1
3
----------
1
2

下面显示了示例第一部分中分配的工作方式:

 a, _, _
 ^  ^  ^
 |  |  |
[1, 2, 3, 4]

无论如何,如果你去掉左边的第二个下划线变量,那么a将被赋予相同的东西。摆脱两个下划线变量怎么样?

a = *[1, 2, 3, 4]
p a

--output:--
[1, 2, 3, 4]

没有。所以左边的第一个下划线变量似乎是必要的。但是,还有另一种语法可以在不使用尾随下划线变量的情况下获得相同的结果:

a, = *[1, 2, 3, 4]
p a

--output:--
1

因此,第三个例子:

a, *_ = *foo

也可以写成:

a, = *foo 

从而避免尾随下划线变量。

最后,风格指南提供了这个神秘的建议:

当赋值左侧定义了 splat 变量,并且 splat 变量不是下划线时,尾随下划线变量是必需的。

我认为这可能指的是这样的事情:

*a = *[1, 2, 3, 4]
p a

--output:--
[1, 2, 3, 4]

如果要a分配数组的前三个元素,则必须编写:

*a, _ = *[1, 2, 3, 4]
p a

--output:--
[1, 2, 3]

无论出于何种原因,解析器都无法处理:

*a, = *[1, 2, 3, 4]

--output:--
*a, = *[1, 2, 3, 4]
     ^
1.rb:6: syntax error, unexpected '\n', expecting :: or '[' or '.'

这是一个很好的例子:

*a, b, _ = *foo

如果您想将第二个分配给 foo 的最后一个元素,则结尾的下划线变量是必需的b

下面的好例子有点令人困惑:

a, _b = *[1, 2, 3, 4]
a, _b, = *[1, 2, 3, 4]

让我们尝试一下:

a, _b = *[1, 2, 3, 4]
p a, _b

puts "-" * 10

a, _b, = *[1, 2, 3, 4]
p a, _b

--output:--
1
2
----------
1
2

在 ruby​​ 中,诸如变量名之类的变量名与名为or_b的变量没有什么不同。在像 Erlang 这样的函数式语言中,变量和具有不同的效果——但在 Ruby 中则不然。_b__BB

顺便说一句,我不会花五分钟来学习那种风格——它太深奥了。

于 2015-10-08T04:55:19.240 回答
1

在变量前加下划线_没有任何语法意义,它只是一个约定(即,它不是一个严格的规则,并且总是可以在不破坏代码的情况下被破坏)。

它在 Ruby 中不经常使用,但它是 Ruby 中的对应物,用于@在 LaTeX 编程中为函数添加 at 标记。据我了解,它是用来表达诸如“劣质”、“子程序”、“核心”或“元素”之类的概念。可以认为是“多元化”的反面。

示例 1. 通常将数组的变量名称复数,其元素将使用单数名称引用:

items = [1, 2, 3]
items.each{|item| ...}

这可能有点奇怪,但即使使用非单词变量名引用元素时也会偶尔看到这种做法:

is = [1, 2, 3]
is.each{|i| ...}

现在,假设数组预先用一个单数名称命名,然后您想将元素名称与它区分开来。在这种情况下,您可以在元素名称前加上下划线:

item = [1, 2, 3]
item.each{|_item| ...}

x = [1, 2, 3]
x.each{|_x| ...}

示例 2. 假设您有一个调用另一个方法的方法,而后者仅用作子例程,并且完成了前者的大部分工作。在这种情况下,您可以在后者前面加上下划线:

def foo a, b
  ... # Do something just a bit here
  _foo(a, b)
end
def _foo a, b
  ... # Do still a bit here
  __foo(a, b)
end
def __foo a, b
  ... # Most of the job is done here
end

示例 3. 这有点不同,因为它是硬编码 Ruby 的一部分,它使用两个下划线(而不是一个),并且围绕变量(而不是前置)。有方法send,它调用__send__。这样,即使send重新定义为其他内容,__send__也可以使用。

于 2015-10-08T08:43:43.387 回答