我遵循了Why's (Poignant) Guide to Ruby,通过其他几个指南,到Ruby风格指南,看看Ruby程序员是如何思考的。但这是我第一次看到尾随下划线。这些是什么东西?它们有用吗?如果有用,我们什么时候使用它们?如何将它们与splat操作符一起使用?
(Ruby风格指南链接固定在实际示例中)
合法的变量名是_
。像*_
和*x
是相似的。术语后面的下划线变量实际上指的是赋值语句左侧逗号分隔的一系列变量中的最后一个变量名,例如:
a, b, _ = [1, 2, 3, 4]
splat操作符有两个用途:
- 将数组分解为单个元素。
- 收集物品到数组中。
哪一种情况取决于使用splat操作符的上下文。
以下是Ruby风格指南中说的bad: 的例子a, b, _ = *foo
在该示例中,末尾的下划线变量是不必要的,因为您可以将foo
的前两个元素分配给变量a
和b
,方法如下:
a, b = *foo
下划线变量用于表示我不关心这个变量,因此,如果您想要做的只是分配给a
和b
,则在该示例中不需要它。
这个例子也可能被认为是坏的风格,因为也不需要*
操作符:
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
因此,第三个bad例子:
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中没有。
顺便说一下,我不会花五分钟学习那种风格——它太深奥了。
在变量前加上下划线_
没有任何语法意义,它只是一种惯例(即,它不是严格的规则,可以在不破坏代码的情况下被打破)。
在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__
。