5284

[code]

    arr1 = ["1","2"]
    arr2 = ["3","4"]
    
    [*arr1 + arr2] #=> ["1","2","3","4"]
    
[/code]

となります.

`Array#+` のソースも覗いてみましたがなぜこうなるのかわかりませんでした.

どのようなプロセスでこのような結果が返ってくるのか, よろしければ教えていただけませんか.


CC BY-SA 4.0
2015-01-26T01:09:02.650
5280
2020-05-02T05:51:39.147
2020-05-02T05:51:39.147
19110
7797
question
ruby
rubyの配列の演算 [*arr1 + arr2] の仕組みが分からない


`[*arr1 + arr2]` は `[*(arr1 + arr2)]` と見なされるためです。`*` は配列を展開する用途に使われています。

配列の展開は以下のコードを見ると理解しやすいと思います。

[code]

    args = ["hello, %s", "world"]
    
    # sprintf(["hello, %s", "world"])
    sprintf(args)
    # TypeError: no implicit conversion of Array into String
    
    # sprintf("hello, %s", "world")
    sprintf(*args)
    # => "hello, world"
    
[/code]


CC BY-SA 3.0
2015-01-26T01:54:36.190
5283
2015-01-26T01:54:36.190
76
5280
answer


`Array#+` によって配列が連結されます

[code]

    arr1 + arr2 #=>["1", "2", "3", "4"]
    
[/code]

また、ここでの`*`は配列を以下のように展開します

[code]

    arr = [1,2]
    a, b = *arr #a => 1 b => 2
    a, b = 1, 2 #これと同じ
    
[/code]

`*arr1 + arr2`は`*(arr1 + arr2)`と同義で`"1", "2", "3", "4"` と展開されます。したがって

[code]

    [*arr1 + arr2]
    [*(arr1 + arr2)]
    [*(["1", "2", "3", "4"])]
    ["1", "2", "3", "4"]
    
[/code]

となります


CC BY-SA 3.0
2015-01-26T01:57:10.570
5284
2015-01-26T02:48:14.703
2015-01-26T02:48:14.703
5793
5793
5280
answer


`*`が付いていると可変長要素として解釈されます。  
メソッドの引数や[多重代入](http://docs.ruby-
lang.org/ja/2.0.0/doc/spec=2foperator.html#multiassign)で複数の引数を配列として受けたりその逆にインラインで展開します。  
この場合`arr1 + arr2`で配列が結合されてその内容が配列の中身として展開されます(多重代入の右辺の式に当たる)。


CC BY-SA 3.0
2015-01-26T02:05:29.953
5285
2015-01-26T02:11:24.130
2015-01-26T02:11:24.130
5044
5044
5280
answer


該当コードの動作解釈については @suzukisさん、@yasuさん、@BLUEPIXY さんの解答通りかと思います。

この回答は `*` よりも先に `+` が評価される理由、つまり `[(*arr1) + arr2]` ではなく `[*(arr1 + arr2)]`
と評価される仕組みを、興味本位で[Ruby言語仕様(Draft)](http://www.ipa.go.jp/osc/english/ruby/ruby_draft_specification_agreement.html)から調べた結果となります。

Rubyの（厳密な意味での）単項演算子としては、`-`, `~`, `+`, `!`の4種類しか存在しません。  
つまり単項演算子`*`というものは存在しないので、`[(*arr1) + arr2]`と解釈されることはありえません。ここでの `*` は、文法上は
splatting-argument の一部として解釈されます。

プライマリ式(primary-expression) `[ * arr1 + arr2 ]`
を、Ruby処理系が構文解析していく過程は次の通りです（終端記号への置き換えを伴わない中間過程は全部省略しています）：

  * **`[ * arr1 + arr2 ]`** → **array-constructor** → **`[`** indexing-argument-list **`]`**
  * `[` **`* arr1 + arr2`** `]` → `[` **splatting-argument** `]` → `[` **`*`** operator-expression `]`
  * `[` `*` **`arr1 + arr2`** `]` → `[` `*` **additive-expression** `]` → `[` `*` additive-expression **`+`** multiplicative-expression `]`
  * `[` `*` **`arr1`** `+` **`arr2`** `]` → `[` `*` **variable** `+` **variable** `]`

* * *

文法定義より部分的に引用

> primary-expression ::  
>  array-constructor  
>  | variable-reference  
>  | ...
>
> array-constructor ::  
>  `[` indexing-argument-list _?_ `]`
>
> indexing-argument-list ::  
>  splatting-argument  
>  | ...
>
> splatting-argument ::  
>  `*` operator-expression
>
> operator-expression ::  
>  conditional-operator-expression  
>  | ...
>
> ～
>
> unary-operator-expression ::  
>  unary-minus-expression  
>  | unary-expression
>
> unary-minus-expression ::  
>  power-expression  
>  | `-` power-expression
>
> power-expression ::  
>  unary-expression  
>  | ...
>
> unary-expression ::  
>  primary-expression  
>  | `~` unary-expression  
>  | `+` unary-expression  
>  | `!` unary-expression
>
> variable-reference ::  
>  variable  
>  | ...
>
> variable ::  
>  constant-identifier  
>  | global-variable-identifier  
>  | class-variable-identifier  
>  | instance-variable-identifier  
>  | local-variable-identifier


CC BY-SA 3.0
2015-01-26T08:42:49.173
5323
2015-01-26T10:20:31.407
2015-01-26T10:20:31.407
49
49
5280
answer