だいきちメモリアル

ブログです

公式Perlチュートリアル

先日のブログに書いたとおりPerl公式のチュートリアルを学んでいる。

daikichi.hatenadiary.com

最近WEBフロントエンドのライブラリのチュートリアルをこなすことが多いだが、 これらのチュートリアルは懇切丁寧に記されておりPerlチュートリアルに対しても同じようなものを想定していた。

しかし、内容は最低限Perlの基礎とかコンピュータ・サイエンスの基礎などの知識が必要とされる内容だった。 先にPerlの基礎を学んでいたおかげで特に問題無く読み進めらることができたが、
このチュートリアルは私のチュートリアルに対する概念は大きく崩すことになる内容だ。

さて、このチュートリアルだがちょっとしたジョークを交えた文章で書かれており読んでいると以外に楽しめる内容になっている。 内容もPerlの細かな挙動について触れられており、こういったところに新たな発見・気付きを得られるのは学ぶ上での喜びだろう。

ここから下はチュートリアルで学んだことの覚書を記していく*1

変数の定義

変数の先頭にプレフィクスをつけることで、データのタイプを分類出来る

# スカラーは`$`
$shin_gi = true;
$number = 42;
$string = "moji moji";

# 配列は`@`
@array = ( 1, 2, 3, 4, 5 );

# ハッシュは`%`
%hash = ( "ha" => "shun!!" );
%hash = ( "ali", "as" ); # こう書いてもいいが、分かり難いので多分書かない

尚、配列やハッシュに格納出来るのはスカラー値だけなのでネストするデータ構造などが扱えない。
これを解決するために参照というスカラー値を作って格納するらしい。

# 参照を作るには、配列やハッシュの先頭に`\`をつける
$aref = \@array;
$href = \%hash;

# 無名配列・無名ハッシュへの参照を持てる
# オリジンを壊されないという意味でこっちのほうが使いやすそうだが…
# (メモリ使用量などが問題になるか?)
$aref = [ 1, 2, 3, 4, 5 ];
$href = { "no" => "name" };

# 参照へアクセスしたいときは`{}`でくくることでアクセスできるようになる
@{$aref}       # => @array
${$aref}[0]    # => $array[0]
%{$href}       # => %hash
${$href}{"no"} # => $hash{"no"}

# 参照先の要素アクセスにはエイリアスが存在する(こちらを使ったほうが読みやすくて良い)
$aref->[0]    # ${$aref}[0]
$href->{"no"} # ${$href}{"no"}

正規表現

Perlは文字列操作が凄いというだけあってかなりボリュームが高い内容となっていた。
なので基本的な部分にのみ目を通して読み飛ばした。

以下は基本的な部分の覚書である。

# `=~`演算子でマッチの真偽をチェックできる
if ($value =~ /kihonn/) {
    print "matched!";
}

# `!~`演算子でアンマッチの真偽をチェックできる
if ($value !~ /unmatch/) {
    print "unmatched...";
}

# 正規表現のデリミタは`m`オプションを指定することで変更ができる
"Henkou dekiru!" =~ m{dekiru!};

# グループ化して取り出す
if ("grouping!!" =~ /(ping).*(!!)$/) {
    print $1; # "ping"
    print $2; # "!!"
}

# マッチした値はリストで返るのでこういうふうに書ける
($ping, $bikkuri) = ("grouping!!" =~ /(ping).*(!!)$/);

スレッド

Perlではスレッドを利用することができるらしい。
Perlのスレッドはスレッドセーフらしいので、スレッドを生成した時点でデータがスレッド内にコピーされる。
(配列やハッシュの参照を渡してみたところ、参照すらも(参照先にある実態も)コピーされました)

※スレッドセーフなのは、スレッド生成時にすべてのデータをコピーするから。 データ以外(chdirなどでプロセスレベルで影響を与えるもの)はすべてのスレッドに影響を及ぼしてしまう。

use threads;

# サブルーチンの参照を渡すと、その処理をスレッド内で行ってくれる。
my $thread = threads->create(sub { print "Hello world!!"; })

# `join`メソッドを呼び出すと、スレッドの完了を待機、戻り値がある場合は取得、スレッドの後始末を行ってくれる。
# スレッドの後始末をしないコードはエラーになる。
$thread->join();

# `detach`メソッドはスレッドの後始末を行うだけ。
# スレッドが実行中であっても処理結果が出力される前に`detach`を呼び出せばその結果を得ることは出来ない。
$thread->detach();

上記はスレッドの基本的な利用方法でデータのシェア、キューの存在やセマフォ等も存在しますが、
これらが必要になるケースは稀だろうということで軽く読み進めるだけに留めておいた。*2

オブジェクト

パールのクラスはパッケージ。

package Human;
use Human;

# パッケージ名からメソッドを呼び出せる
Human->Something;

オブジェクトのコンストラクタは、blessを内部で呼び出すサブルーチン。 コンストラクタの名前は何でもよい。

blessは参照をオブジェクトとみなすために利用するらしい(よくわかっていない)

# 内部でblessを呼び出せばそれがコンストラクタ
sub new { bless {} }

# newでなくても良い
sub init { bless {} }

オブジェクトの継承には@ISA構文を利用する。
暗黙的にすべてのオブジェクトはUNIVERSALクラスを継承する。
オブジェクトからメソッドを呼び出すとき、オブジェクトにメソッドがなければ、@ISAで定義したオブジェクトの左からメソッドを探していき、 どこにも無い場合にAUTOLOADメソッドを呼び出す。

{ package Animal;
  sub cry {}
}

{ package Dog;

  # Animalを継承
  @Dog::ISA = qw(Animal);
}

# Dogパッケージにはcryメソッドが無いが、Animalを継承しているので呼び出せる。
Dog->cry;

オブジェクトに関する内容がかなり濃密なので、詳細はまた別途学習することにする。

*1:書いておかないと記憶に定着しないので…

*2:本格的にやると楽しいのだが、その分時間を消費してしまうので…