約3年間での個人的なPerl躓きポイントをまとめてみた

# 初めに
この記事は [Wanoグループ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/wano-group) の17日目の記事になります。

# 序章

※雑な解釈ゆえに間違っていることを書いていたら申し訳ありません。

皆さんPerlは好きでしょうか。僕は(慣れもあり)今は好きと言えますが触り始めてからしばらくは絶望するほど苦手でした。そんな自分が仕事を通じてPerlに慣れるまでにつまずいたりしたポイントを雑に紹介できればと思います。
ちなみにプロジェクトにジョインするまでには大学だったり趣味などでPython3やJava、Golangなどを主に用いておりどちらかといえば型に恵まれていた環境で、Perlに関しては「Perlというプログラミング言語がある」「Perlはテキスト処理が得意」という状態からの開始でした。

# 躓いたポイント

## 変数での「スカラ(`$`)」「配列(`@`)」「ハッシュ(`%`)」を理解する
Perlにおける型は次の3つを覚える必要があります。
* スカラ(`$`)
    * 数字
    * 文字列
    * 配列のリファレンス/ハッシュのリファレンス
* 配列(`@`)
* ハッシュ(`%`)

```perl
# $xxxx でスカラとして定義する。
my $hoge = 1;
my $piyo = "ピヨ";

# @xxxx で配列として定義する。
my @hoge = (1, 2, 3);

# %xxxx でハッシュとして定義する。
my %hoge = (1 => "hoge", 2 => "piyo");
```
最初に困らされたのは「数字～型」とか「文字列～型」とかではなく「スカラ」で1つの型というところでした。
また、ここでいう配列のリファレンス・ハッシュのリファレンスというのはものすごく雑に言うと「配列やハッシュのアドレス」ということです。
静的な型の言語を中心にやってきた自分には一番最初に？となったところです。この区別を最初にインプットするべきでした。

```perl
my @hoge = (1, 2, 3);
# $piyoは@hogeを参照している
my $piyo = \@hoge;
push @$piyo, 4, 5, 6;
# @hoge = (1, 2, 3, 4, 5, 6);
```


## 「偽」「定義されていない」を理解しよう
Perl上での偽は以下の5つです。条件分岐を記述する時に「何が真で何が偽だっけ」というのは記憶しておきたいところです。
* `0` (数字)
* `"0"` (文字列)
* `""` (空文字列)
* `undef` (未定義)
* 空のリストやハッシュ(リファレンスではない!)

```perl
my $hoge = 0;
# 真 or 偽で言えば偽
if ($hoge) {
    print("true\n")
} else {
    print("false\n")
}
# false

# 定義 or 未定義で言えば定義されている
if (defined($hoge)) {
    print("defined\n")
} else {
    print("not defined\n")
}
# defined
```


## 「空のリスト(ハッシュ)」と「空のリスト(ハッシュ)のリファレンス」の違いに気を付けよう
「空のリスト(ハッシュ)」は false 扱いだが「空のリスト(ハッシュ)を参照しているリファレンス」は「参照しているリスト(ハッシュ)がある」 => true となるという少しややこしいポイントが存在するため気を付けたいところです。

```perl
use Data::Dumper;
# (1) 
my @hoge = ();
if (scalar(@hoge)) {
    print Dumper "true";
}

# (2)
my $hoge = \@hoge;
if ($hoge) {
    print Dumper "truetrue";
}
# (3)
if (scalar(@$hoge)) {
    print Dumper "truetruetrue";
}
``` 

↓↓

```shell
$ perl main.pl
$VAR1 = 'truetrue';
```

## 「リストの連結」と「多次元リストを作る」の違いの理解
データ構造で良くある多次元リスト(多次元配列)をPerlで作る際引っかかりやすい(と思っている)ポイントがあります。
```perl
my @hoge = (1, 2, 3);
my @piyo = (4, 5, 6);
```

Perlの配列の要素は「スカラ」の決まりがあるため、以下のように書くと多次元リストを作らず「リストの連結」になります。
```perl
my @bar = (@hoge, @piyo);
# @bar = (1, 2, 3, 4, 5, 6);

push @bar @hoge;
# @bar = (1, 2, 3, 4, 5, 6, 1, 2, 3);
```

多次元リストを作るためには配列のリファレンス(=スカラ)を入れれば良いです。

```perl
my @bar = (\@hoge, \@piyo);
# @bar = ([1, 2, 3], [4, 5, 6]);
# [1, 2, 3]
# [4, 5, 6]


push @bar \@hoge;
# @bar = ([1, 2, 3], [4, 5, 6], [1, 2, 3]);
# [1, 2, 3]
# [4, 5, 6]
# [1, 2, 3]
```

## 組み込み関数「grep」「map」を使えるようにしよう
`grep`, `map` の2つの関数が分かるようになれば飛躍的に読み書きしやすくなります。

### grep
配列 `@a` の中で条件を満たすものだけ取り出せる。
```perl
my @a = (1, 2, 3);
# 2で割ったあまりが0の要素だけ取り出す
my @b = grep {$_ % 2 == 0} @a;
# @b = (2);
```
### map
配列 `@a` の各要素を変換できる。
```perl
my @a = (1, 2, 3);
# すべての要素を2倍する
my @b = map {$_ * 2} @a;
# @b = (2, 4, 6);
```




## 正規表現を抑える
Perlは直接的に正規表現を使っていけるので、今まで関数やパッケージを呼び出して正規表現を使う言語を使っていた自分としては面食らった記憶があります。
### マッチ
```perl
my $hoge = "hoge";
# 含んでいる
if ($hoge =~ /og/) {
    # OK
}
# 含んでいない
if ($hoge !~ /og/) {
    # NG
}
```
### 置換
```perl
my $hoge = "hoge";
$hoge =~ s/hoge/piyo/;
# $hoge = "piyo";
```

# 最後に
Perlは他の言語と比べると迷ったり、「それ実行できるの？」など結構ありますが慣れてくると使いやすいく良くできてるなと思わされます。
Perlを実際に使ってみるとテキスト処理もそうですが、個人的には配列やハッシュの扱いもかなり使いやすくサクサク記述できてデータの整形などに積極的に使っていけそうだなというポジションになりました。今回でPerlの最初の「そこに気をつければいいんだ」と「データ整形で使いやすい」を共有できれば幸いです。

ぜひPerl、いかがでしょうか。

# 参考文献
最終閲覧日 2022年12月8日
https://perlzemi.com/