Perl/変数、データ構造

出典: フリー教科書『ウィキブックス(Wikibooks)』

プログラミング > Perl > 変数、データ構造

ここではPerlの変数とデータ構造についての基本的な事項を学びます。応用的な事項についてはリファレンスで触れます。

目次

[編集] 変数とは

変数の概念について説明します。変数とは一言で言えばデータを格納する領域です。変数を用いることにより、データをより柔軟に扱うことができます。

変数の利用の形態は大きく分けて代入参照展開の3種です。

[編集] データ構造の種類

[編集] スカラー

スカラーとは内部に構造をもたない「ただ一つ」の形をもっているデータ構造です。

$name = "太郎";
#$nameに太郎を代入している
$age = 30;
#$ageに30を代入している

変数$nameに"太郎"、変数$ageに"30"というように一つの変数に対して単体のデータが保存されます。

スカラーに限らず、変数には"太郎"のような文字列や30のような数値を区別なく含めることができます。原則的に文字列を扱う場合には「"」や「'」で囲みます。数値の場合は「"」や「'」は必要ありません。

[編集] 配列、リスト

配列、リストは順序付きの複数のデータからなるデータ構造です。ここでいう順序付きとは「配列の最後にデータを付け加える」「前から順番にデータを読み込んで画面に出力する」「1番目のデータを読み込むとともにデータから削除する」といった、順序が存在していることを前提にした処理が可能であるということです。配列とリストは似通っていますが区別する必要があります。

@name = ("太郎", "次郎");
#@nameは配列、("太郎", "次郎")はリスト
($name1, $name2) = @name;
#($name1, $name2) はリスト、@nameは配列

[編集] ハッシュ

ハッシュとは、キーと値がペアになったデータ構造です。

%age = (
    太郎 => 30,
    二郎 => 20,
);
print $age{太郎}; # 30

このように、キーの文字列でアクセスすると対応する値が得られます。キーは必ず文字列として扱われます。

=>演算子はコンマ演算子と同じ働きをしますが、左オペランドの値を必ず文字列として扱うため、ハッシュを生成するときに多く用いられます。また、コンマを使うよりもキーと値の対応が明確になるという利点もあります。

ハッシュはキーと値が関連付けられたリストです。配列はデータの並び順が決まっていますが、ハッシュはランダムに格納されるため、データの順番が保証されません。ただ、キーと値がペアになっているということのみが保証されます。

%age = (
    太郎 => 30,
    二郎 => 20,
);
print %age; # 太郎30二郎20 あるいは 二郎20太郎30

[編集] Perlが扱うデータ

他言語と比べ、Perlでは文字列と数値の区別は曖昧で、良く言えば柔軟で直感的である。

下記の実行結果は52になる。(文字列は数値として解釈されるときは0として扱われる。)

$a = 52;
$b = "nd street";
print $a + $b;

これの実行結果は"52nd street"になる。

$a = 52;
$b = "nd street";
print $a . $b;

[編集] 文字列

長さに制限のない文字列です。 実際にはどんなビット列でも格納でき、(Cなどの言語と違って)NULL (\0) を文字列中に含めることさえできます。

Perlには1文字だけを格納する文字型は存在しません。文字を1つだけ格納している文字列として表現します。

[編集] 数値

環境に依存する実数です。 10進数, 2進数(先頭に0bを付加する), 8進数(0を付加する), 16進数(0xを付加する)によって数値を表現できます。 また、科学的記数法による表現も可能です:

print 5e3; #5000

表現できる数値の範囲は環境に依存しますが、無限長の実数を表現できるMath::BigFloatなどのモジュールが用意されています。

[編集] リファレンス

後の章で詳しく説明しますが、他のデータを参照するデータです。 複雑なデータ構造を構築したり、Perlのオブジェクト指向機能を使う際に重要なデータ型です。

[編集] 特殊変数

[編集] コンテキスト

変数、関数、定数などが、式の中でどのように評価されるか決定するものです。
大別するとスカラ・コンテキストとリスト・コンテキストがあり、スカラ・コンテキストにおかれた値はスカラとして、リスト・コンテキストにおかれた値はリストとして評価されます。
コンテキストと実際のデータが食い違っている場合、次のような規則で評価されます。

  • スカラ・コンテキストにリストがおかれた場合、リストの最後の要素が評価されます(コンマ演算子の為)。
  • リスト・コンテキストにスカラがおかれた場合、そのスカラ1個だけを要素とするリストであると解釈されます。

どのようにコンテキストが提供されるか、以下にいくつか例を示します。

代入式は右辺に、左辺と同じコンテキストを提供します:

my @array = qw(Foo Bar Baz);
my $var = @array; #3が代入される

配列はスカラ・コンテキストで評価されるとその要素数を返すので、結果として$numberには3が代入されます。
ただしこのような結果になるのは配列だけです。 前述したとおり、通常のリストがスカラ・コンテキストで評価されると、最後の要素が返されます:

my $var = qw(Foo Bar Baz); #'Baz'が代入される



my ($foo, $bar, $baz) = 'Foo'; #リスト・コンテキスト

右辺はスカラですが、左辺がリスト値を期待している為、1つの要素'Foo'のみを持つリストと解釈されます。 これが$fooに代入されますが、残りの2つの変数については、対応する右辺値がない為未定義となります。
したがって、これは次のコードと等価です:

my ($foo, $bar, $baz) = ('Foo', undef, undef);



フォワード宣言されたサブルーチンは、デフォルトで引数にリスト・コンテキストを提供します:

sub user_func;
user_func 'foo', 'bar', 'baz';

これは次のように解釈されます。

user_func('foo', 'bar', 'baz');

つまり、括弧のないサブルーチン呼び出しはリスト演算子として扱われます。
もしこれを、

user_func('foo'), 'bar', 'baz'

と解釈させたいのなら、フォワード宣言にプロトタイプを付加することによって単項演算子として解釈させることができます:

sub user_func($); #実装にもプロトタイプが必要
user_func 'foo', 'bar', 'baz';

サブルーチンとフォワード宣言、プロトタイプについての詳細はサブルーチンを参照してください。

スカラ・コンテキストはさらに文字列、数値、真偽値、無効コンテキストに細分され、評価されます。

[編集] 文字列コンテキスト

長さに制限のない文字列として扱われます。
数値はそのまま文字列に変換され、未定義値は空文字列になります。リファレンスも文字列になりますが、文字列として処理されたリファレンスを再びリファレンスに戻すことはできません:

my ($var, $refvar, $refstr);
$var = 'foo';
$refvar = \$var; #$$refvar eq 'foo'
$refstr = "$refvar"; #文字列として格納
$$refstr; #エラー; $refstrはもはやリファレンスではない

[編集] 数値コンテキスト

10進数の表記に使われる文字列は数値として扱われます。それ以外の文字があるとそこで解釈が終了します。

#全て12345と解釈される。
my $numstr = '12345';
my $numstr2 = '12345abcde';
my $numstr3 = '123.45e2';

先頭に'0'や'0x'があっても8進数や16進数とは解釈されないので注意が必要です。この場合 oct() 関数や hex() 関数を利用します。

my $numstr4 = '012345'; #12345; 8進数ではない
my $numstr5 = '0x12345'; #0; 'x'で解釈が終了する

組み込みの算術演算子は、オペランドに対して数値コンテキストを提供します。 よって、値に0を足すことで強制的に数値として解釈させることができます:

print '12345abcde', "\n"; #12345abcde
print '12345abcde' + 0, "\n"; #12345

[編集] 真偽値コンテキスト

ifやwhileなどの制御構文や修飾文、andやorなどの論理演算子が提供するコンテキストです。
偽となるものは:

であり、残りは全て真と解釈されます。 「文字列'0'」とは'0'という文字列のことであり、数値コンテキストで0と解釈される文字列全てのことではないので注意してください。
次のものは全て真となります:

'0.0';
'aaa';
'0 but true';

[編集] 無効コンテキスト

評価した結果が捨てられてしまうので、値を期待しないコンテキストです。戻り値のない関数呼び出しなど、副作用を目的として使われます。
副作用もないコードは、perlに-wスイッチをつけて実行すると警告が発せられます:

'literal';

[編集] 型グロブ

Perlでは異なるデータ構造に対して同じ識別子を与えることができます:

$foo = 'bar';
@foo = ( 'bar', 'baz' );
%foo = ( bar => 'baz' );
sub foo { return 'bar' };

Perl処理系は内部に識別子テーブルと呼ばれるハッシュを持っています。そのキーは識別子であり、対応する値は型グロブというデータ構造です。型グロブは同じ識別子を持つすべてのデータ構造へのリファレンスを格納しています。つまり上記の例だと識別子'foo'の型グロブにはスカラー、配列、ハッシュ、サブルーチンという4つのデータ構造へのリファレンスが格納されています。型グロブは識別子の前に'*'というプレフィックスを付加して表現されます:

*foo;

型グロブ自身はリファレンスを格納したハッシュであり、キーはデータ構造の名前です:

*foo{SCALAR}; # \$foo
*foo{ARRAY};  # \@foo
*foo{HASH];   # \%foo
*foo{CODE};   # \&foo
*foo{GLOB};   # \*foo; 自分自身へのリファレンス
*foo{IO};     # ファイルハンドル
*foo{FORMAT}  # フォーマット

[編集] 型グロブへの代入

型グロブもデータ構造の一つですから、代入や評価ができます。型グロブに別の型グロブを代入すると、変数の別名(エイリアス)を定義することが出来ます:

$foo = 'FOO';
@foo = ( 'FOO', 'BAR' );
*bar = *foo;

$bar = 'BAR';
push( @bar, 'BAZ' );

print $foo, "\n"; #BAR
print @foo, "\n"; #FOOBARBAZ

これはかつてPerlにリファレンスがなかった頃、サブルーチンに引数を参照渡しするのに利用されていました。また、ファイルハンドルとフォーマットにはプレフィックスが存在しないので、これらを受け渡しする場合の唯一の手段でもありました。

for ( $i = 0; getline( *line ) != -1; $i++ ) {
    print "line $i: $line";
}

sub getline {
    local (*l) = @_;
    return defined( $l = <STDIN> ) ? length( $l ) : -1;
}

現在ではリファレンスが利用できるので、型グロブを使う必要はありません。ファイルハンドルやフォーマットに関してもIOモジュールなどでオブジェクトとして扱うことができます。

なお、型グロブは識別子テーブルの実体そのものですから、ブロックに結び付けられたレキシカルスコープにすることはできません。言い換えると、local変数にはできるがmy変数にはできません。

また、特定のデータ型のリファレンスを代入すると、そのデータ型に限定して別名を定義できます:

$foo = 'FOO';
@foo = ( 'FOO', 'BAR' );
*bar = \@foo; #配列のみ別名を定義

$bar = 'BAR';
push( @bar, 'BAZ' );

print $foo, "\n"; #FOO
print @foo, "\n"; #FOOBARBAZ
*qux = \&Foo::Bar::baz; # Foo::Barモジュールのbaz関数をqux関数としてインポートする
このページ「Perl/変数、データ構造」は、書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にノートへどうぞ。
ヘルプ