複数の値をまとめて代入(多重代入)

代入文の左辺と右辺に複数の変数や式を書くことで、1つの代入文でまとめて複数の代入を実行できるものを言語によっては多重代入という。名称は言語によって違うかもしれないが、似たような仕組みがいくつかの言語にある。

Scala

左辺に複数の変数名を書いて、右辺の値を1つ書くと、すべての変数に同じ値を束縛する。

val a, b, c = 10;
// a => 10
// b => 10
// c => 10

val a, b, c = (10, 20, 30);
// a => (10, 20, 30)
// b => (10, 20, 30)
// c => (10, 20, 30)

左辺の複数の変数名を () で囲めば、右辺はタプルを置く必要があり、タプルの要素ごとに変数に束縛できる。

val (a, b, c) = (10, 20, 30);
// a => 10
// b => 10
// c => 10

// 以下はコンパイル時に型がマッチしないエラー
// 左辺がタプル型で、右辺が整数のため
// val (a, b, c) = 10;

以下は、コンパイル時の構文エラーになる。

// 以下はコンパイル時に構文エラー
// val (a, b, c) = 10, 20, 30;

varで宣言された可変の変数に対する再代入ではタプルの要素ごとの代入ができないみたい。

var (a, b, c) = ...;
...;
// 以下はコンパイル時にエラー
(a, b, c) = (10, 20, 30);

PHP

list($a, $b) = array(1, 2);
// $a => 1
// $b => 2

listは関数ではなく構文で、こういうときのために使う言語構造である。

右辺の要素の数のほうが多い場合は、余計な要素は切り捨てられる。

左辺の変数のほうが多い場合は、 PHP Notice: Undefined offset: 1 というようなNoticeが発生し、余計な変数は NULL になる。以下のように @ をつけるとNoticeは発生しない。

@list($a, $b) = array(1, 2);

-> 配列(リスト)の範囲外のインデックスにアクセスしたときにどうなるか?

list | PHP Manual
http://php.net/manual/ja/function.list.php

Python

リストやタプルを右辺に置けば、要素ごとに左辺の変数に代入できる。アンパック代入という。

式の優先順位をコントロールするための () と混同する可能性がなければ、タプルは () を省略し , だけでも表せる。

a, b = [3, 'abc']
a, b = (3, 'abc')
a, b = 3, 'abc'
# a => 3
# b => 'abc'

右辺はリストやタプルにかぎらず、同じくシーケンスと呼ばれるカテゴリに属する文字列を置くこともできる。

Python2の場合

a, b, c = u'あいう'
# a => 'あ'
# b => 'い'
# c => 'う'

Python3の場合

a, b, c = 'あいう'
# a => 'あ'
# b => 'い'
# c => 'う'

複数の変数を = で区切って並べればすべての変数に同じ値を代入することができる。これはマルチターゲット代入という。

a = b = c = (1, 2, 3)
# a => (1, 2, 3)
# b => (1, 2, 3)
# c => (1, 2, 3)

マルチターゲット代入とアンパック代入を組み合わせることもできる。

lst = [1, "abc"]
a = (b, c) = lst
print(a, b, c)

# Python2での出力
# ([1, 'abc'], 1, 'abc')

# Python3での出力
# [1, 'abc'] 1 abc

Ruby / JRuby

= を複数並べれば、複数の変数に同じ値を代入できる。

a = b = 3
puts a # => 3
puts b # => 3

コンマ区切りで複数の変数への代入をまとめてできる。(多重代入)

a, b = 3, 'abc'
puts a # => 3
puts b # => abc

右辺は配列にしてもよい。

a, b = [3, 'abc']
puts a # => 3
puts b # => abc

メソッド呼び出し時と同様に * で配列を展開したり、逆に配列で受け取ったりできる。

a, *b = [1, 2, 3]
print a # => 1
print b # => [2, 3]

a, b, c = 1, *[2, 3, 4]
print a # => 1
print b # => 2
print c # => 3

a, b, *c = 1, *[2, 3, 4]
print a # => 1
print b # => 2
print c # => [3, 4]

多重代入 | Ruby 2.1 リファレンスマニュアル
http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2foperator.html#multiassign

Perl

左辺の複数の変数名を () で囲んで、右辺にリストを書けば、それぞれを代入できる。my を書けば変数の宣言も兼ねることができる。

my @arr = (10, 20, 30);
my ($a, $b, $c) = @arr;
# $a => 10
# $b => 20
# $c => 30

my @arr = (10, 20, 30);
my ($a, $b) = @arr;
# $a => 10
# $b => 20

my @arr = (10, 20, 30);
my ($a, @b) = @arr;
# $a => 10
# $b => (20, 30)
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。
スポンサーリンク