Perlの変数は他のプログラミング言語より特徴的な形をしています。変数が変数の識別子のように扱えるリファレンスもとても特徴的な機能です。他にもダイヤモンド演算子(<>)はPerlのコードであればよく見るもので使いこなすことができればとても強力な機能になります。
また、この記事で利用しているPerlのバージョンはv5.32.1になります。
目次
変数
Perlの変数は、数値等のデータやリファレンス(スカラー)、配列(スカラーの配列)、ハッシュ(スカラーのハッシュ)で形が変化します。
スカラー:
ex) $var = 100;
ex) $ref = \$var; $arrayref = \@array; $hashref = \%hash
配列:
ex) @vararray = (100,200,300,'str');
ハッシュ:
ex) %varhash = ( 'aaa', 100, 'bbb', 200, ccc, 300);
ex) %varhash = ( 'aaa' => 100, 'bbb' => 200, ccc => 300, ); #リストの最後にカンマをつけても良い
※裸の単語(引用符なしの文字列)は、特定の文字列(予約語や組み込み関数)以外は、引用符があるように通常の文字列として扱われます。
スカラー、配列、ハッシュの変数は変数名が同じ場合でも別々のものとして扱われます。
このperlの変数のルールは変数を左辺値として利用する場合は、上記のような利用方法で問題ありませんが、右辺値として変数を利用する場合は、少しめんどうだと感じるかもしれません。
変数を右辺値として扱う場合でもこのルールを適用して、単数や複数かを意識して変数を呼び出す必要があります。
test.pl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/bin/env perl use feature 'say'; $var = 1; @var = (2,3,4); %var = (aaa,5,bbb,6,ccc,7); say "$var"; say "$var[0]"; say "$var{aaa}"; say "@var[1,2]"; say "@var{bbb,ccc}"; |
実行結果
1 2 3 4 5 6 |
$ ./test.pl 1 2 5 3 4 6 7 |
また、配列やハッシュのようなリストは評価が行われるときに、基本的にスカラーに展開されます。
1 2 |
$ perl -E '@ary1=(2,3); @ary2=(1,@ary1); say "@ary2"' 1 2 3 |
2次元配列のようなものはリファレンスを用いて実現できます。
配列のリファレンスは角括弧('[]')を用いることで利用できます。
1 2 3 4 |
$ perl -E '$ref = [1,2,[3,4,5]]; say "$ref->[2][1]"' 4 $ perl -E '@ary=(3,4,5); $ref = [1,2,[@ary]]; say "$ref->[2][1]"' 4 |
ハッシュのリファレンスは波括弧('{}')を用いることで利用できます。
1 2 3 4 |
$ perl -E '$ref = {aaa,1,bbb,2}; say "$ref->{bbb}"' 2 $ perl -E '%hash=(ccc,3); $ref = {aaa,1,bbb,2,%hash}; say "$ref->{ccc}"' 3 |
変数の解釈はどのような関数かで変化する場合があります。
関数がリストを取る基本的な宣言(リスト演算子になる関数の宣言)の例
1 |
sub func {} |
関数のプロトタイプ宣言によって、変数の解釈が変化します。
関数がリストを取る宣言の例
1 |
sub func (@) {} |
関数が引数を1つ取る宣言(単項演算子になる関数の宣言)の例
1 |
sub func ($) {} |
関数が引数を2つ取る宣言の例
1 |
sub func ($$) {} |
関数が引数を取らない宣言(定数関数として利用可能)の例
1 |
sub func() {} |
裸の単語(barewords,ベアワード)
裸の単語が利用される場合は以下の例があります。
- 文字列
- ハッシュ
- ファイルハンドル
基本的に文字列として解釈されますが、使い方によっては関数なのか裸の単語なのか判別が難しい場合があるので、use strict 'subs'がある場合に裸の単語が許されなくなる場合があります。ただし、ハッシュのキー('$var{aaa}')やハッシュの=>での使用('%var=(aaa=>1)')は許されます。
1 2 3 4 5 6 7 8 9 |
$ perl -e '$var = aaa; print "$var\n"' aaa $ perl -e 'use strict "subs"; $var = aaa; print "$var\n"' Bareword "aaa" not allowed while "strict subs" in use at -e line 1. Execution of -e aborted due to compilation errors. $ perl -e 'use strict "subs"; %hash = (aaa=>1); print "$hash{aaa}\n"' 1 $ perl -e 'use strict "subs"; $hashref = {aaa=>1}; print "${$hashref}{aaa}\n"' 1 |
古いPerlコードでのファイルハンドル
古いPerlのコードでは(予約語のSTDINやSTDOUT等ではない)裸の単語をファイルハンドルとして用いている場合があります。
これはPerlの(新しい関数が追加される等の)将来の予約語に小文字が使われる可能性があるため、大文字を使って記述されます。
この裸の単語はファイルハンドルのために特別にグローバル変数として利用できますが、
予約語ではない裸の単語にファイルハンドルを割り当てて利用する方法はあまり推奨された方法ではありません。
例えば、
1 |
open(FH, "<", "input.txt"); |
と
1 |
open(my $fh, "<", "input.txt"); |
は後者の書き方のほうが良いとされています。
リファレンスとデリファレンス
ハッシュの値はスカラー値でなければなりません。ハッシュの値にリスト等の値を必要とする場合はリファレンスを利用することができます。
この概念はPerlのオブジェクト指向プログラミングにも利用されます。
また、デリファレンスはリファレンスで参照しているデータを実際のデータに返す操作になります。
リファレンスの作成
それぞれのスカラーやリスト等からのリファレンス作成は、バックスラッシュ演算子を利用することで作成できます。
1 2 3 4 5 |
$scalarref = \$foo; $arrayref = \@ARGV; $hashref = \%ENV; $coderef = \&handler; $globref = \*foo; |
匿名配列のリファレンスは角括弧を用いると作成できます。
1 |
$arrayref = [1, 2, [31, 32, 33]]; |
匿名ハッシュのリファレンスは波括弧を用いると作成できます。
1 2 3 4 5 6 7 8 9 |
$hashref1 = { 'hash_key1' => 'hash_value1', 'hash_key2' => 'hash_value2' } $hashref2 = { hash_key1 => 'hash_value1', hash_key2 => 'hash_value2' } |
匿名のサブルーチンのリファレンスも作成できます。
1 |
$coderef = sub { print "hello\n" }; |
他にもリファレンスの作成にはオブジェクトのコンストラクタ等もあります。
1 |
$obj = Dog->new( kind => 'Shiba' ); |
リファレンスの利用(Simple Scalar)
変数の識別子は、'$val = 1'だったらvalの部分は識別子といえます。リファレンスのスカラー変数は、識別子のように利用できます。
つまり、リファレンスのスカラー変数を$refとすると、例えば、$$refのようにすることで参照している値を利用できます。
参照しているものを配列として扱うなら@$ref、ハッシュとして扱うなら%$refのように変数を利用するルールは適用されます。
さらに配列やハッシュの要素は
1 2 3 4 5 |
$arrayref = [1,2,3]; print $$arrayref[0]; $hashref = {key1 => 'value1', key2 => 'value2'}; print $$hashref{key1}; |
のように利用できます。ここで、リファレンスと要素を指定する'[0]'や'{key1}'の結びつきについて、丸括弧で表して、考えると
1 2 |
( ($$arrayref) [0] ) ( ($$hashref) {key1} ) |
として見ることができます。
1 2 3 |
$val = 1; $ref = \\\$val; print $$$$ref; |
のようなコードがある場合は、
1 |
($ ($ ( $$ref) ) ) ) |
のように見ることができ、リファレンスが識別子のようになり、また、そのリファレンスが識別子のようになり、もう一回、そのリファレンスが識別子のようになって、目的の値になるというイメージができます。
リファレンスの利用(BlOCK)
変数や関数の識別子は解釈を分かりやすくするために、波括弧を用いてブロック(BLOCK)にすることができます。
例えば、リファレンスのスカラー変数$refを用いて、リファレンスが単純な数値等のスカラー値を指し示す場合は、${$ref}のように利用できます。
1 2 3 4 |
$arrayref = [1,2,3]; print ${$arrayref}[0]; $hashref = {key1 => 'value1', key2 => 'value2'}; print ${$hashref}{key1}; |
リファレンスの利用(Arrow Notation)
配列やハッシュのリファレンスや、関数のリファレンスの呼び出しで$$refや&$refのように、先頭に2つの記号が出るような記述が頻繁に出る可能性があります。
配列やハッシュのリファレンスでの要素や、関数のリファレンスでの呼び出しにはシンタックスシュガーとして矢印記法(Arrow Notation)があります。
つまり、
1 2 3 |
$$arrayref[0] = 1; $$hashref{key} = 1; &$coderef(1,2,3); |
は
1 2 3 |
$arrayref->[0] = 1; $hashref->{key} = 1; $coderef->(1,2,3); |
のように記述することができます。
また、'配列->ハッシュのリファレンス->配列のリファレンス'というような構造のデータは、
1 |
array[0]->{key}->[0] = 1; |
のように記述できますが、角括弧([])や波括弧({})のようなそれぞれの括弧間の->はオプションで省略可能になるため
1 |
array[0]{key}[0] = 1; |
のように記述できます。
3次元配列のようなものを作成したい場合は
1 2 3 |
@array = ([[1,2],[3,4]],[[5,6],[7,8]]); print $array[0][0][0],"\n"; print $array[1][1][1],"\n"; |
のように記述できます。配列の要素は$array[0]のように指定でき、その後のリファレンスでは、括弧間の->は省略可能なため、C言語のような3次元配列のような記述ができます。
また、すべてを配列のリファレンスで作成すると、その要素の指定方法は
1 2 3 |
$arrayref = [[[1,2],[3,4]],[[5,6],[7,8]]]; print $arrayref->[0][0][0],"\n"; print $arrayref->[1][1][1],"\n"; |
のようになります(これは1行目の一番外側の丸括弧が角括弧に代わって、配列リファレンスを作成してます)。
括弧間の矢印は省略できますが、リファレンスの変数と括弧の間の矢印は省略できないため、このような記述になります。
リファレンスの利用(後置のデリファレンス)
perl v5.20以降の機能でuse feature 'postderef'の宣言が必要でしたが、v5.24以降では宣言が不要です。
これを利用すると、リファレンスを左から右に読む形式を取ることができます。
1 2 3 4 5 6 7 |
$ref->$*; # ${ $ref } $arrayref->@*; # @{ $arrayref } $arrayref->$#*; # $#{ $arrayref } $hashref->%*; # %{ $hashref } $coderef->&*; # &{ $coderef } $globref->**; # *{ $globref } $globref->*{SCALAR}; # *{ $globref }{SCALAR} |
リファレンスの利用(ハードリファレンスとシンボリックリファレンス)
ハードリファレンスは以下のような例になります。
use strict 'refs'はシンボリックリファレンスを禁止します。
1 2 3 4 5 6 |
use strict 'refs'; use feature 'say'; $ref = \$value; $$ref = 3; say $value; |
通常、リファレンスを利用する場合、識別子のようになるのはリファレンスになります。
これに対して、シンボリックリファレンスは、リファレンスとして利用する値に文字列の定義があった場合に、その値を識別子として利用した変数を利用できます。
no strict 'refs'はシンボリックリファレンスを許します。
これは強力な機能ですが、ハードリファレンスを利用しようとして意図せず利用されてしまう可能性があることに注意が必要です。
1 2 3 4 5 6 |
no strict 'refs'; use feature 'say'; $ref = 'value'; $$ref = 3; say $value; |
特徴的な演算子
繰り返し演算子:
perlの繰り返し演算子は、'x'を用います。
文字列結合:
perlの2つの文字列の結合は'.'を用います。
名前付き単項演算子とリスト演算子:
関数の引数に括弧を用いない場合の言い方で、引数が一つのもの(名前付き単項演算子)だったり、複数の引数を取ることができる演算子(リスト演算子)のことになります。
自作関数は基本的にリスト演算子で利用することができます。関数のプロトタイプ宣言を利用すると単項演算子として利用することもできます。
ダイヤモンド演算子:
・<FILEHANDLE>の用法でreadline関数のようにファイルから行を読み取ることができます。
スカラーコンテキストではファイルから一行ずつ読み取ります。以下のコードは等価になります。
1 2 |
while(<STDIN>){ print; } while($_ = <STDIN>) { print; } |
補足として、
1 2 |
while(<>){ print; } while($_ = <>) { print; } |
の2行のコードは、@ARGVが空の場合はSTDINから読み込まれます。@ARGVがある場合は、そのARGVのファイルを開いて読み取っていきます。
その疑似コードは以下のようになります。
1 2 3 4 5 6 7 |
unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } } |
リストコンテキストではファイルの終端まで行を読み取ります。
便利ですが、簡単にメモリを消費できてしまうことに注意が必要かもしれません。
list_readline.pl(元の行と行をソートしたものを表示)
1 2 3 4 5 6 |
use feature 'say'; @lines = <>; say @lines; say sort(@lines); |
利用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ cat text.txt aaa bbb ccc ddd eee $ shuf text.txt | perl list_readline.pl ccc bbb ddd aaa eee aaa bbb ccc ddd eee |
・<*.c>の用法でglob関数のようにシェル(csh, bash等)のTABを押したときのファイル名が補間されたときのようなリストを返します。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ ls *.txt data.txt data2-1.txt data2.txt data3.txt text.txt $ perl -E 'while(<*.txt>){ say; }' data.txt data2-1.txt data2.txt data3.txt text.txt $ perl -E 'while(<data{,?}.txt>){ say; }' data.txt data2.txt data3.txt |
参考
perlの公式サイト
The Perl Programming Language - www.perl.org
perlのドキュメントを日本語に翻訳しているサイト
perldoc.jp