鱒身(Masu_mi)のブログ

知った事をメモする場所。

初めてのPerlコーディング

前に遊ぶ準備や環境準備を書いたので使ってみた時に覚えておこうって思った特徴・ライブラリ・ツールについてメモしておく。

データ型は3つ

公式ドキュメントのデータ型 を読んでおけば良い。 読んだら下の使い方があって興味を持った。

@days[3,4,5] # as ($days[3], $days[4], $days[5])

外部モジュールを読み込む

use, require 命令の2つが存在する。

use, require を比較する

命令 評価タイミング 使えるサブルーチン バージョン
use コンパイル時評価 BEGIN, CHECK, INIT >= 5系
reuqire 実行時評価 BEGIN 全バージョン

use はコンパイル時評価であり特別なコードブロックを定義可能で、これらはモジュール読み込み時等に実行可能。

BEGIN 出来るだけ早く実行される(パース直後など)
END 出来るだけ遅く実行される(プログラム終了時など, シグナルで撃沈されたりevalだと実行されない, LIFO実行)
UNITCHECK 対象コンパイル単位のコンパイル直後に実行される
CHECK 最初のコンパイルフェーズ終了後に実行開始(LIFO)
INIT ランタイム実行直前(FIFO)

ref. Perlのモジュール

PATHを追加する

相対パスで読み込み先を指定したくなる。そういう時はFile, lib モジュールを使う。 以下を読み込む前に追加しておけば../lib/ 配下を探索する様になる。

use File::Basename;
use lib dirname(__FILE__). "/../lib/";

ファイルを行単位で処理する

行単位で処理するには以下のスニペットが綺麗な感じがする。行入力演算子<> を利用してファイルハンドラから受け取る。 標準入力は特別なファイルハンドラSTDIN から受け取る。 行末のEnter も入力に含まれる。chomp 関数で行末Enter を削除するのが良い。

open (IN, $file_name) or die "$!";
my $line;
while (<IN>) {
  $line = $_;
  chomp($line);
  print $line;
}

ガード節

異常な入力値を弾くためガード節を使うが、Perlでは後置を使う事がある。

$v = "apple"
print "v is apple." if $v eq "apple"
print "v is not orange." unless $v eq "orange"

定義済み変数

perlvar を参考にすると良い。以下抜粋。

$_ デフォルト入力などのスペース
@_ , @ARG サブルーチンの引き数が入っている・配列演算子のデフォルト引き数
%SIG シグナルハンドラを持つハッシュ
$PID , $$ プログラムのPID
$BASETIME , $^T ブログラムが起動したUnixTime

定番の正規表現処理

置換、存在の判別は以下の様にする。デフォルトでは$_ が対象になる。() を使ってキャプチャを行なう。

if (/pattern/) {
  print '$_ にpatternが含まれる';
}
if (!/pattern/) {
  print '$_ にpatternが含まれない';
}
if ($word =~ /pat(tern)/) {
  print '$word にpatternが含まれる';
  print $1; # ternが含まれる
}
if ($word !~ /pattern/) {
  print '$word にpatternが含まれない';
}
if (m|pattern|) {
  print 'm でパターン文字を変更する';
}

die, exit関数

異常系の処理には2つの方法がある。 1つめはdie 関数で例外を発生させる方法。 2つめはexec 関数でプロセス終了させる方法。

die 関数

詳細はリンク先を読めば良い。die 関数は例外を発生させるのでeval ブロックに囲まれてない場合、プログラムを終了させる。 eval に囲まれている場合はdie に渡した値が$@ に格納されるので以下の様に使う事になる。 サブルーチン外部でエラーを捕捉しようとしてる可能性がある場合はこれをつかう。

eval {
  die "in eval";
}
if $@ {
  print "error処理". $@;
}

これを応用したError <http://search.cpan.org/~shlomif/Error-0.17022/lib/Error.pm> モジュールが存在する。これを使うとtry, catch, except, throw などが使える様になる。

exit 関数

evalで捕捉されずプログラムを終了させる。各モジュールのEND サブルーチンを実行してから終了する。 引き数には終了コードを渡す。

サブルーチンの宣言・定義

組み込み関数一覧 を参考にする。 全ての引き数・返り値はスカラのリストに潰される。リスト・ハッシュともに潰されて渡される。 サブルーチン内部では@_ として見える。リスト・ハッシュの構造を失わずに渡すには参照渡しを行なう必要がある。

プロトタイプ宣言

& を使わない呼び出しで組み込み関数の様に振る舞わせる事が可能で、その受け取り方を定める。 下みたいな感じでブロックを受け取るサブルーチンを作ったり出来る。

sub safe(&@) {
  my $code = shift;
  start()
  eval {
    $code->();
  }
  if $@ {
    print "error"
  }
  end()
}

カリー化とか関数中心な書き方をするためのモジュールも存在するから、その辺を参考に使い方を覚えるとよさそう。 functionals

bless 使ってクラスを定義する

Perlでオブジェクト を参考に書けばだいたいOK。 メソッド、継承、委譲、オーバーライドとか出来る。 肝はbless を使いオブジェクトを与えたパッケージ名と結びつけパッケージ内のサブルーチンをオブジェクト経由で呼べる様にする事。 これがメソッドになる。 そしてメソッドの呼び出しは第1引き数にインスタンスが入ってくる。 パッケージでの-> 呼び出しでは先頭にクラス名が入っているという事。

package ClassName;
sub new {
  my ($class, $arg) = @_;
  $self = {}
  bless $self, $class
  return $self
}
package main;
$a = Classname->new();

tie の使い方

オブジェクトをメソッド経由でアクセスさせる代わりにネイティブなデータ型としてアクセスさせる方法がある。 tie 関数はスカラ・配列・ハッシュ・ハンドラとしてオブジェクトを結びつけられる。 詳細はリンクから読めばよし。TIESCALAR, FETCH, STORE などを定義して使う。PHPでのArrayObjectインタフェースの実装を書くみたいな感じ。

local, my を使った変数の名前解決

localは動的スコープ, myは静的スコープで名前解決を行なう。

global変数は名前空間を明示して利用する

したみたいな感じ

$::val = "global variable";
sub hoge {
  print $::val;
}
hoge;
# $VAR1 = 'global variable';

コマンドオプション解析の方法

Getopt::Long モジュールが定番でバッドノウハウが溜まっているらしい。 バッドノウハウと注意点はこの記事 がまとまっているらしい。

テストコードの書き方

Test::More パッケージが単体テストが気楽な定番っぽい。 マニュアル読めば直ぐに使える。perlのテストコードの拡張子はt が使われる。

Data::Dumper でプリントでバッグ

ここ を参考にすると良いです。 http://bayashi.net/diary/2013/0415

他の言語を利用したい

使わなかったけれど選択肢は以下があるみたい。

Inline::C 他のプログラム言語で直接Perlサブモジュールを作る
XS 外部のCコード, Cライブラリを利用する
Swig 級言語でC/C++を使うためのツール(perlも可能 )