【问题标题】:why does ruby parallel assignment with array of strings returns string为什么带有字符串数组的ruby并行赋值返回字符串
【发布时间】:2013-02-16 18:41:29
【问题描述】:

我不确定下面的代码 sn-p 到底发生了什么。

>> a, b = ["ho", "hey"]
=> ["ho", "hey"]
>> a
=> "ho"
>> b
=> "hey"    
>> c, d = "foo", "bar"
=> ["foo", "bar"]
>> c 
=> "foo"
>> d
=> "bar"
>> a, b = ["blerg"], ["baz"]
=> [["blerg"], ["baz"]]
>> a
=> ["blerg"]
>> b 
=> ["baz"]

为什么第一行不返回a => ["ho"]

那么在幕后,这三个作业(a, b = ["ho", "hey"]c, d = "foo", "bar"a, b = ["blerg"], ["baz"])有什么区别?

【问题讨论】:

    标签: ruby


    【解决方案1】:
    a, b = ["ho", "hey"] 
    

    a 分配给数组的第一个元素,即字符串“ho”。没什么奇怪的。

    a, b = ["blerg"], ["baz"]
    
    a, b = [["blerg"], ["baz"]]
    

    这两个是相同的,从它们的返回值可以看出。所以 a 被分配了第一个元素,它是一个包含一个元素的数组:["blerg"]

    同样,

    c, d = "foo", "bar"
    

    是一样的

    c, d = ["foo", "bar"]
    

    【讨论】:

    • 当心 a = b = []。有时我打算 a,b = [],而不是写 a = b = []。而后者会将b的引用分配给a,这不是您想要的。捐赠
    【解决方案2】:

    在 Ruby 中,= 在左侧获取变量列表,在右侧获取表达式列表。它将第一个变量分配给第一个表达式的值,将第二个变量分配给第二个表达式的值,依此类推。如果变量多于表达式,剩余的变量将被赋值为nil

    > a, b, c, d = "foo", 2+3, Array.new(2, 3), [:c, :d]
    > a     # => "foo"
    > b     # => 5
    > c     # => [3, 3]
    > d     # => [:c, :d]
    > e     # => nil
    

    有两个例外:

    左边只有一个变量,右边有多个表达式

    在这种情况下,上面的规则会说变量只是被设置为右边第一个表达式的值。相反,该变量被设置为由右侧表达式的值组成的数组。在下面的示例中,我们看到a 获得值[:b, :c],而不仅仅是:b

    > a = :b, :c
    > a    # => [:b, :c]
    

    这相当于:

    > *a = :b , :c
    > a    # => [:b, :c]
    

    另一个例外:

    左边有多个变量,右边只有一个表达式并且是一个数组

    同样,原始规则意味着第一个变量被设置为整个数组,其余变量为零。但是,该数组实际上最终会被其元素列表替换,然后 = 恢复为开头所述的“默认”行为:

    > a, b, c = [:d, [:e, :f]]
    > a    # => :d
    > b    # => [:e, :f]
    > c    # => nil
    

    这相当于a, b, c = *[:d, [:e, :f]],或者只是a, b, c = :d, [:e, :f]

    【讨论】:

    • 不知道左侧一个变量的情况。酷!
    【解决方案3】:

    在您指出的示例中,多重赋值的右侧使用了 2 种不同的结构:

    一个简单数组的多重赋值

    array = ["item1", "item2"]
    a, b = array
    # a => "item1"
    # b => "item2"
    

    数组的多重赋值,其元素本身就是单元素数组(又名:多维数组)

    array = [["item1"], ["item2"]]
    a, b = array
    # a => ["item1"]
    # b => ["item2"]
    

    多重赋值仅展开多维数组的第一层,并允许您将这些元素分配给表达式左侧的多个变量。因此,当您使用多维数组执行此操作时,它将第一个元素["item1"] 分配给a,然后移动到下一个元素["item2"] 并将其分配给b .多重赋值不会“深入”到多维数组中,而是从第一级元素开始赋值。

    【讨论】:

      【解决方案4】:

      Ruby 语言中的赋值运算符允许Multiple assignments(又名:并行赋值)。

      在赋值运算符 (=) 的左侧说 lvalue 左侧变量或属性,并说 rvalue 右侧值。

      通过多重赋值你可以将一个逗号分隔的列表赋值给另一个,左边的对应变量从右边获取对应的值

      第一次并行分配

      a, b = ["ho", "hey"]
      

      如果最后一个 rvalue 是一个数组,您可以在它前面加上一个星号,这有效地将它扩展为它的组成值。 如果 rvalue 是右侧唯一的东西,则不需要星号数组将自动展开

      为了更好地理解,试试这个:

      >> a,b,c =  "1",*["ho", "hey"]
      => ["1", "ho", "hey"]
      >> a
      => "1"
      >> b
      => "ho"
      >> c
      => "hey"
      

      让我们再看看:

      >> a,b,c =  "1",["ho", "hey"]
      => ["1", ["ho", "hey"]]
      >> a
      => "1"
      >> b
      => ["ho", "hey"]
      >> c
      => nil
      

      如您所见,如果我们不以 * 为数组前缀,则数组不会展开。

      第二次并行分配

      c, d = "foo", "bar"
      

      “foo”、“bar”是两个literal Strings赋值给左侧对应的变量。

      第三次并行分配

      a, b = ["blerg"], ["baz"])?
      

      ["blerg"]["baz"] 是两个 Array,每个数组包含一个 String 类的元素;

      因此每个“单个字符串的数组”都分配给左侧的相应变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-27
        • 2019-06-13
        • 2020-03-30
        • 2012-05-24
        • 1970-01-01
        • 2020-07-31
        相关资源
        最近更新 更多