Perlの変数（スカラー、配列、ハッシュ）とリファレンスについて

# はじめに

Perlにはリファレンスというものがあり、初めて扱う人にとっては混乱の元でしょう。でも、Perlを扱う上で避けては通れません。「何でわざわざリファレンスにするんだ」と思うかもしれませんんが、リファレンスにするのはちゃんと理由があります。その理由を知れば、積極的にリファレンスを使いたくなることでしょう。

# リファレンスを扱うメリット

## ①処理が高速になる

**Perlのリファレンスは変数の実体を参照するもの**です。C言語でいうとポインタ、Macでいうとエイリアス、Windowsでいうとショートカット、Linuxでいうとシンボリックリンク。ファイルそのものをコピーするとすごい時間がかかりますが、エイリアスを作るだけなら一瞬で済みます。

実はPerlでは関数などに変数を渡すと実体を渡してしまうので、大容量のデータが格納された変数を渡すと時間がかかります。でもリファレンスならデータを参照するメモリのアドレスが記録されているだけなので時間がかかりません。

## ②多次元配列を作れる

実を言うと**Perlの配列は一次元しか扱えません。**例えば配列を多次元にしようと思っても以下のようになります。

```perl:多次元のつもりが一次元になってしまう
my @x = ("A", "B", "C");
my @y = ("D", "E", "F");
my @z = (@x, @y); # @z = ("A", "B", "C", "D", "E", "F")
```

でも**リファレンスなら多次元も扱えます。**配列をリファレンスに変換して渡すことで多次元に扱うことができます。

```perl:リファレンスを使えば多次元にできる
my @x = ("A", "B", "C");
my @y = ("D", "E", "F");
my @z = (\@x, \@y);

print $z[1][2]; # F
```

いちいち変数を作らずとも、最初からリファレンスで作ればスッキリします。

```perl:最初からリファレンスで定義する
my $z = [
  ["A", "B", "C"],
  ["D", "E", "F"]
];

print $z->[1][2]; # F
```

## ③サブルーチンに複数の配列やハッシュを渡せる

**Perlでサブルーチンの引数に値を渡すと `@_` という特殊変数にひとつの配列として渡されます。**単体のスカラー変数を渡す分には問題ないのですが、配列を混ぜたり、複数の配列を渡そうとしたりすると、`@_` ではそれらがつながったひとつの配列に統合されてしまいます。

```perl:２つの配列として渡せない
sub func {
    my (@a, @b) = @_;
    print "@a, @b\n";  # @a に全て代入されてしまう。@b は何も入っていない
}

func((1, 2), (3, 4));  # 1 2 3 4,
```

でも、サブルーチンにリファレンスを渡すようにすればこの問題は解決します。**参照先が配列でもハッシュでも、リファレンスを格納する変数は常にスカラーになります。**常にスカラーなので、配列のリファレンスを引数で渡せば `@_` で配列に統合されても一つ一つは配列のリファレンスのままです。あとはサブルーチン側でリファレンスから配列を取り出せばよいわけです。

```perl:リファレンスを渡せばサブルーチン側で配列を取得することができる
sub func {
    my ($a, $b) = @_;
    print "@$a, @$b\n";
}

func([1, 2], [3, 4]);  # 1 2, 3 4
```

# リファレンスの扱い方

## スカラー

```perl
# 代入
my $a = 100;

# 出力
print $a;  # 100
```

## スカラーのリファレンス

いきなりリファレンスに代入するには無名変数を使います。いきなりリファレンスに代入するので、実体を示すスカラー変数はありません。

```perl
# 代入（無名変数を参照）
my $b = \do {'b'};
my $c = \'c';

# 出力（どちらの書き方でもよい）
print ${$b};  # b
print $$b;  # b
print ${$c};  # c
print $$c;  # c
```

## スカラー変数からリファレンスへの変換

スカラーからリファレンスに変換するには変数の頭にリファレンス演算子（`\`）をつけます。

```perl
my $a = 100;
my $d = \$a;  # リファレンスへ変換

print $$d;  # 100
```

## 配列

配列は頭に `@` を付けます。

```perl
# 代入
my @a = (1, 2, 5);

# 出力
print $a[1];  # 2

# 配列全体の出力
$, = ", ";  # printのための出力フィールドの区切り文字を指定する特殊変数
print @a;  # 1, 2, 5
```

## 配列のリファレンス

配列は頭に `@` を付けますが、リファレンスはスカラー変数なので頭には `$` を付けます。

```perl
# 代入（無名配列を参照）
my $b = [1, 2];

# 出力（どちらの書き方でもよい）
print $b->[1];  # 2
print ${$b}[0];  # 1

# 配列全体の出力（どちらの書き方でもよい）
$, = ", ";
print @{$b};  # 1, 2
print @$b;  # 1, 2
```

## 配列からリファレンスへの変換

配列からリファレンスに変換するには変数の頭にリファレンス演算子（`\`）をつけます。

```perl
my @a = (1, 2, 5);
my $c = \@a;  # リファレンスへ変換

$, = ", ";
print @$c;  # 1, 2, 5
```

## ハッシュ

ハッシュは頭に `%` を付けます。

```perl
# 代入
my %a = (foo => 1, bar => 2);

# 出力
print $a{foo};  # 1

# ハッシュ全体の出力
$, = ", ";
print %a;  # bar, 2, foo, 1
```

## ハッシュリファレンス

ハッシュは頭に `%` を付けますが、リファレンスはスカラー変数なので頭には `$` を付けます。

```perl
# 代入（無名ハッシュを参照）
my $b = {foo => 100, bar => 200};

# 出力（どちらの書き方でもよい）
print $b->{foo};  # 100
print ${$b}{bar};  # 200

# ハッシュ全体の出力（どちらの書き方でもよい）
$, = ", ";
print %{$b};  # bar, 200, foo, 100
print %$b;  # bar, 200, foo, 100
```

## ハッシュからリファレンスへの変換

ハッシュからリファレンスに変換するには変数の頭にリファレンス演算子（`\`）をつけます。

```perl
my %a = (foo => 1, bar => 2);
my $c = \%a;  # リファレンスへ変換
$, = ", ";
print %{$c};  # bar, 2, foo, 1
```

# 最後に

リファレンスを使う理由が分かれば使うモチベーションも上がりますね。扱い方も法則が分かればそれほど難しくありません。むしろ「全部リファレンスでいいんじゃね」と思ってしまいますが、shift、unshift、pop、pushなどの配列に関する関数は、引数は配列でなければなりません。値を渡す際はデリファレンスする必要があるので注意してください。

```perl
# デリファレンスして標準関数に渡す
shift @$array_ref;
unshift @$array_ref, $s;
push @$array_ref, $s;
pop @$array_ref;
```