【发布时间】:2016-01-05 12:59:06
【问题描述】:
我已经关注Why's (Poignant) Guide to Ruby,通过其他几个指南,到Ruby style guide,了解 Ruby 主义者的想法。 但这是我第一次看到尾随下划线。这些是什么?它们有用吗?如果有用,我们何时使用它们以及如何将它们与 splat 运算符一起使用?
(Ruby 风格指南链接锚定到实际示例)
【问题讨论】:
标签: ruby-on-rails ruby splat
我已经关注Why's (Poignant) Guide to Ruby,通过其他几个指南,到Ruby style guide,了解 Ruby 主义者的想法。 但这是我第一次看到尾随下划线。这些是什么?它们有用吗?如果有用,我们何时使用它们以及如何将它们与 splat 运算符一起使用?
(Ruby 风格指南链接锚定到实际示例)
【问题讨论】:
标签: ruby-on-rails ruby splat
合法的变量名是_。像*_ 这样的东西类似于*x。术语结尾的下划线变量实际上是指赋值语句左侧以逗号分隔的一系列变量中的最后一个变量名,例如:
a, b, _ = [1, 2, 3, 4]
splat 运算符有两种用途:
发生哪些情况取决于使用 splat 运算符的 上下文。
以下是 Ruby 风格指南所说的不好的示例:
a, b, _ = *foo
该示例中的尾随下划线变量 是不必要的,因为您可以通过以下方式将foo 的前两个元素分配给变量a 和b:
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 中,诸如 _b 之类的变量名与名为 _ 或 b 的变量没有什么不同。在像 Erlang 这样的函数式语言中,变量 _ 和 _B 和 B 具有不同的效果——但在 Ruby 中则不然。
顺便说一句,我不会花五分钟来学习那种风格——它太深奥了。
【讨论】:
*a, = ... 的原因与它不能处理*a, *b = ... 的原因相同:它如何决定在a 中放入多少项目,在b 中放入多少?或者在*a, = ... 的情况下,它如何决定在a 中放入多少项以及忽略多少项?它不能,所以解析器甚至不允许它。
*a,,用结果是a 等于除最后一个元素之外的整个数组。
x 和 _x 和 _ 之间没有区别。当你看到*_ 时会有点困惑,但这相当于*x。下划线只是对读者的一个提示,取自函数式语言,该变量不会被使用。
*a, *b = ... 它只是意味着“把其他所有东西都扔掉”。当它跟随一个 splat 变量时,将其含义更改为“扔掉最后一个元素”没有任何意义。
a, = *[1, 2, 3, 4] 导致a #=> 1。我可能在您的回答中错过了它,但是当您移除 splat 时会获得相同的结果。 a,_ = [1,2,3,4] 很常见,但实际上只需要逗号。
在变量前面加上下划线_ 没有任何语法意义,它只是一个约定(即,它不是一个严格的规则,并且总是可以在不破坏代码的情况下被破坏)。
它在 Ruby 中并不经常使用,但它是 Ruby 中的对应物,用于在 LaTeX 编程中为函数添加 @ 标记。据我了解,它是用来表达诸如“劣质”、“子程序”、“核心”或“元素”之类的概念。可以认为是“多元化”的对立面。
示例 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__ 也可以使用。
【讨论】:
__foo 将同时用于foo 和_foo,则可以。人们在相当宽松的解释下使用它,所以你不需要太认真地对待它。