dreamedge.net

Rubyにおける多重代入の文法

2008-08-23T09:51:00+0000
id, domain, = 'foo@bar.com'.split('@')

みたいな式でよく使う多重代入.ある種Rubyの特徴とも言えるのだけど,あまりちゃんと意識したことがなかったので調べなおしてみた.

Rubyマニュアルの多重代入の説明や,多重代入のFAQを読んでもピンとこなかったので,自分なりに整理しなおしてみた.

基本形:カンマ区切り

代入の左辺,右辺共に’,’で区切ることで複数の要素を指定できる.複数の変数を初期化するのに便利.

i, j, k = 1, 2, 3 # i=1; j=2; k=3

一方の要素の方が多かった場合は,多いほうの値は無視される.

i, j, k    = 1, 2, 3, 4 # i=1; j=2; k=3

この場合,kには3が代入されて,右辺の最後の要素である4は無視される.

i, j, k, l = 1, 2, 3 # i=1; j=2; k=3; l=nil

この場合,左辺の方が多いのでkに3が代入されて,l=nilとなる.

基本形:右辺での配列利用

右辺が配列の場合,その内容が展開して代入される.要素の過不足については,コンマ区切りの時と同様の処理になる.

i, j, k    = [1, 2, 3]    # i=1; j=2; k=3
i, j, k    = [1, 2, 3, 4] # i=1; j=2; k=3
i, j, k, l = [1, 2, 3]     # i=1; j=2; k=3; l=nil

使っちゃダメ!?:左辺での配列利用

左辺の変数が1つの場合配列とみなして代入される.結構多用するケースだが,マニュアルに1.9以降でエラーになる可能性が指摘されている.今後はあまり使わないようにしないと.

a = 1, 2, 3 # a=[1,2,3]

応用形:’*’を使った配列への代入

配列名の左に’*’を付けると,自動的に展開したものとして扱ってくれる.上で左辺に配列を使うのはダメと書いたけど,それを解決する手法.

*a = 1, 2, 3 # a=[1,2,3]

右側の要素数が多い場合に,余剰分を配列とするのにも使える.

i, j, *a = 1, 2, 3, 4, 5 # i=1; j=2; a=[3,4,5]
i, j, *a = 'id,date,a,b,c'.split(',') # i='id'; j='date'; a=['a','b','c']

’*’が使えるのは左辺の最後の変数のみ.そこ以外に使うとエラーとなる.

i, *a, j = 1, 2, 3, 4, 5 # SyntaxError: compile error
*a, i, j = 1, 2, 3, 4, 5 # SyntaxError: compile error

応用形:’*’を使って配列を展開する

配列名に’*’を使う手法は,右辺でも同様に使える.普通の変数と配列を混ぜて代入したいときに便利.付けないと配列がそのまま要素として代入されてしまう.

i, j, k = 1,  [2, 3] # i=1; j=[2,3]; k=nil
i, j, k = 1, *[2, 3] # i=1; j=2; k=3
*a = 1,  [2, 3] # a=[1,[2,3]]
*a = 1, *[2, 3] # a=[1,2,3]

右辺の場合も’*’がつけられるのは最後の要素のみ.以下の場合はエラーとなる.

*a = *[1,2], 3, 4 # SyntaxError: compile error
*a = 1, *[2,3], 4 # SyntaxError: compile error
*a = 1, 2, *[3,4] # a=[1,2,3,4]

ちなみに*を付けた記述ができるのは以下の5通りらしい.これを見ると引数の受け渡しに多重代入と _ほぼ_ 同じルールが適用されているのが分かる.

  • 多重代入の左辺
  • 多重代入の右辺
  • 引数リスト(定義側)
  • 引数リスト(呼び出し側)
  • caseのwhen節

発展形:要素記述の省略

カンマで式を終わらせたり,’*’の後に何もつけないことにより余った要素を省略することが可能.

i, j, * = 1, 2, 3, 4 # i=1; j=2
i, j,   = 1, 2, 3, 4 # i=1; j=2

使い道がすぐには思いつかない表記法だけど,配列の頭の要素だけとりたいときに使える.けどあまり使うべきではないと思う.

i  = [1, 2, 3] # i=[1,2,3]
i, = [1, 2, 3] # i=1

i  = 1, 2, 3   # i=[1,2,3]
i, = 1, 2, 3   # i=1

発展形:括弧を使ってネストした配列に対応する

括弧を使うと,右辺がネストした配列の場合に対応できる.’*’での配列展開は一番右の要素にしか使えないので,右辺の途中に配列を置く場合に使える.非常にややこしいので,例を見て理解するのが一番.

 i, j,  k = [1, 2], 3 # i=[1,2]; j=nil; k=3
(i, j), k = [1, 2], 3 # i=1;     j=2;   k=3

i,  j, k,  l = 1, [2, 3], 4 # i=1; j=[2,3]; k=4; l=nil
i, (j, k), l = 1, [2, 3], 4 # i=1; j=2;     k=3; l=4

この括弧をネストして使うことも可能.

i,  j,  k, l   = 1, [2, [3, 4]] # i=1; j=[2,[3,4]]; k=nil; l=nil
i, (j, (k, l)) = 1, [2, [3, 4]] # i=1; j=2;         k=3;   l=4