在Ruby中使用带有splats的下划线

时间:2015-10-08 04:37:38

标签: ruby-on-rails ruby splat

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

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

2 个答案:

答案 0 :(得分:8)

合法变量名称为_*_之类的内容与*x类似。术语尾随下划线变量实际上是指赋值语句左侧的逗号分隔变量系列中的最后一个变量名,例如:

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

splat运算符有两个用途:

  1. 将数组分解为各个项目。
  2. 将项目收集到数组中。
  3. 其中发生的情况取决于使用splat运算符的 context

    以下是Ruby样式指南所说的 bad

    的示例
    a, b, _ = *foo
    

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

    a, b = *foo
    

    下划线变量用于表示,我不关心此变量,因此在该示例中没有必要将所有要执行的操作分配给{{1} }和a

    该示例也可能被视为错误的样式,因为也不需要b运算符(credit: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
    

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

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

      

    当存在splat时,必须使用尾随下划线变量   在赋值左侧定义的变量,以及splat   变量不是下划线。

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

    a, = *foo 
    

    如果你想为*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 '.'
    

    如果你想将第二个元素分配给foo的最后一个元素*a, b, _ = *foo ,那么尾随的下划线变量是必要的。

    以下好例子有点令人困惑:

    b

    让我们尝试一下:

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

    在ruby中,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 等变量名称与名为_b_的变量没有区别。在像Erlang这样的函数式语言中,变量b_以及_B具有不同的效果 - 但不是在Ruby中。

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

答案 1 :(得分:1)

使用下划线_添加变量没有任何语法含义,它只是一个约定(即,它不是严格的规则,并且可以在不破坏代码的情况下始终打破)。

在Ruby中并没有经常使用它,但在Ruby中,在LaTeX编程中使用at标记@预先添加一个函数。据我所知,它用于表达诸如"劣等","子例程","核心"或"元素&#34这样的概念;。它可以被认为是"多元化"的对立面。

示例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__