Perl の変数・リスト・配列・ハッシュ・リファレンス・デリファレンス

# 変数・リスト・配列・ハッシュ・リファレンス・デリファレンス
Perl を始めたんですが PHP に比べて配列やハッシュの書き方が独特で覚えにくかったのでまとめました。
## 変数
`$` が先頭につく変数はスカラー変数
1行しかかけない紙切れ1枚のようなもの
数値・文字列かリファレンス（スカラー値）しか入らないし、どれか1種類しか入れることはできない
*リファレンスについては後述
PHPみたいに変数に配列やハッシュを直接ぶちこめない

```perl
$var1 = 0;        # 数値
$var2 = "string"; # 文字列

print $var2; # string
# ""内だと変数は展開される
# 必要なら \ でエスケープする
print "\$var2 is $var2"; # $var2 is string
```

## リスト・配列
`@` が先頭につく変数は配列
スカラー値をいっぱいいれておけるファイルキャビネット、上から順番に入れていく
()で囲むとリスト、配列に代入するときはリストで一気に入れるか `$arr[0] = value;` の形でひとつずつ入れるかの二択

```perl
# $arr1 = (1, 2, 3) はできない、
# $ は文字列や数値を入れられるのであってリストは入れられないことを覚えておく
my @arr1 = (1, 2, 3);
my @arr2 = ("abc", "def", "gh");

# 配列内の値を取り出すときは $arr[i] でアクセスできる
# 配列内の値はスカラー値なのでアクセスするときは $ になる、ちょっと混乱する
print $arr1[0]; # 1
print $arr2[2]; # gh

# 実は @arr[i] でもアクセスできるが、strictが有効になっていると
# Scalar value @arr1[0] better written as $arr1[0] 
# (@arr1[0]じゃなくて$arr1[0]って書け)と怒られる
print @arr1[0]; # 1 

# 配列をそのまま print にかけると全部繋げられて出てくる
# ""でくくると半角スペースで区切られて出てくる
print @arr2;   # abcdefgh
print "@arr2"; # abc def gh
```

## ハッシュ
`%` が先頭につくとハッシュ
目印がついた紙（スカラー変数）が箱の中に無造作に入れられている感じ
PHPで言えば連想配列
同じキーで代入されると一番最後に代入されたものが残る

```perl
# 初期化
my %hash1 = ('key1', 1, 'key2', 2, 'key3', 'val1');

# こう書いても良い（こっちのが見やすい）
my %hash2 = (
    key1 => 1,
    key2 => 2,
    key3 => 'val1',
);

# ハッシュも配列と同じように print にかけると全部繋げられて出てくる
print %hash2;   # key11key22key3val1
print "%hash2"; # %hash2 ハッシュは""内で展開されない

# 値にアクセスするには $hash{key} {}に注意
# もちろんハッシュの値もスカラー値なのでアクセスするときは $ になる
print $hash2{key1}; # 1
```

## リファレンス
参照のこと
変数のメモリアドレスを指し示している
スカラ変数リファレンス・配列リファレンス・ハッシュリファレンス・サブルーチンリファレンスなどがある

### 配列リファレンス
2次元配列をつくりたい場合に必要

```perl
# NG
my @arr1 = (1, 2, 3);
my @arr2 = (4, 5, 6);

my @arr2d = (@arr1, @arr2);
print $arr2d[0][0]; # 1 ...とはならずエラーになる
```
配列はスカラ値しか要素に持てないので配列の中に配列を直接入れられない
じゃあどうやって配列に配列を入れようか？
配列変数のアドレスはスカラ値じゃん、これを値として配列に入れれば2次元配列になるよやったね

```perl
# OK
my @arr1 = (1, 2, 3);
my @arr2 = (4, 5, 6);

my @arr2d = (\@arr1, \@arr2);
print $arr2d[0][0]; # 1
print $arr2d[0]; # ARRAY(0x26ed520) メモリアドレスが入っている
```
#### デリファレンス
ちょっとまって、じゃあ `$arr2d[0]` の中身は (1, 2, 3) のはずだけどそれを見たいときはどうすんの？
そこで登場するのがデリファレンス
メモリアドレスから実際にそのアドレスの配列に入っている値をとってくる
ちょっと""内の変数展開と似てるかも、@{memaddress}でメモリアドレスを展開、と考えてもいいかもしれない
配列リファレンスのデリファレンス、とか言うらしいけどこんがらがりまくる

```perl
# $arr2d[0] (ARRAY(0x26ed520)) をデリファレンス！
print @{$arr2d[0]}; # 123

my $deref1 = $arr2d[0];    # ARRAY(0x26ed520) array2d[0]のメモリアドレスを代入
my @deref2 = @{$arr2d[0]}; # (1, 2, 3) array2d[0]のアドレスの配列を代入

my @deref3 = @$arr2d[0]; # エラー
```
インデックスの[]があるときは {} が必須、ないときは {} を省略してもいい
#### 無名配列
リファレンスだけがほしいときにいちいち配列を初期化してそれのリファレンスを代入して… ってのはめんどくさい

```perl
my $anonyarr_ref = [1, 2, 3, 4];
print $anonyarr_ref; # ARRAY(0xf539e8)
print $anonyarr_ref->[0]; # 1 リファレンスから要素にアクセス

# 無名配列のリファレンスで2次元配列を初期化
my @arr_with_ref = (
    [1, 2, 3],
    ["a", "b", "c"],
);
```
なにが嬉しいのかというと簡単に配列の初期化ができること

### ハッシュリファレンス
配列の値をハッシュに、ハッシュの値をハッシュにしたいときに使う

```perl
my %hash1 = (a => 1, b => 2, c => 3);
my %hash2 = (d => "d", e => "e", f => "f");
my @arr_hash = (\%hash1, \%hash2);

print $arr_hash[0]; # HASH(0x6755c0)
print $arr_hash->[0];
```

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

```perl
print %{$arr_hash[1]}; # ffddee (並び方は固定されていない)
```

#### 無名ハッシュ
配列と同じように簡単にハッシュが書けるので嬉しい
サブルーチンに引数としてハッシュを渡す必要があるけどもいちいち宣言初期化するのはめんどくさいときに使う

```perl
my $anonyhash_ref = { key1 => 1, key2 => 2, key3 => 'val1'};
print $anonyhash_ref; # HASH(0x2663c70)

# 無名ハッシュのリファレンスを使って2次元ハッシュを初期化
my $hash_with_ref = {
    hash1 => {
        key1 => 1,
        key2 => 2,
        key3 => "val3",
    },
    hash2 => {
        key4 => "a",
        key5 => "b",
        key6 => "c",
    },      
};

print $hash_with_ref->{hash1}; # HASH(0x1083ca8)
print $hash_with_ref->{hash2}{key4}; # a
```
### サブルーチンリファレンス

```perl
sub test_method {
    print "This is test method\n";
}
my $sub_ref = \&test_method; # CODE(0x6738e8)

# サブルーチンリファレンスから呼び出す
# () 内には引数が入る
$sub_ref->(); # This is test method
&$sub_ref();  # This is test method
```
#### 無名サブルーチン

```perl
my $anony_sub = sub { print "This is anonymous sub routine\n" };

print $anony_sub; # CODE(0x25827e8)
$anony_sub->();   # This is anonymous sub routine
```

## まとめ

```perl
# スカラ変数
my $sca = 1;

# 配列変数
my @arr = (1, 2, 3);
print $arr[0]; # 1
# 配列のリファレンス
my $arr_ref = \@arr; # ARRAY(0x2733040)
# 無名配列のリファレンス
my $arr_anonyref = [1, 2, 3]; # ARRAY(0x2713fb0)
print $arr_anonyref->[1] # 2
# 配列のリファレンスのデリファレンス
my @arr_deref = @{$arr_anonyref}; # (1, 2, 3)

# ハッシュ
my %hash = ( key => 'value' );
print $hash{key}; # value
# ハッシュのリファレンス
my $hash_ref = \%hash; # HASH(0xfa3ee0)
# 無名ハッシュのリファレンス
my $hash_anonyref = { key2 => 'value2' };
print $hash_anonyref->{key}; # value2
# ハッシュのリファレンスのデリファレンス
my %hash_deref = %{$hash_anonyref}; # key2value2

# サブルーチン
sub test { print "This is test" };
# サブルーチンのリファレンス
my $sub_ref = \&test; # CODE(0xfa3a00)
# 無名サブルーチン
my $anony_sub_ref = sub { print "This is anonymous sub routine" }; # CODE(0xfa3910)
# リファレンスからサブルーチンを呼び出し
$anony_sub_ref->();
```