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