一日ズレてしまったが、Perlのエラーメッセージのコーナー。
2週間に一度、水曜日は、Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。
そのはずであったが、最近はCPANモジュールのインストールの方法を書いていて、しばらくご無沙汰になってしまった。
今回は
これは、
(主語S):%s argument
(動詞V):is
(補語C):not a HASH or ARRAY element or slice
という第2文型の文で、
(主語S):%s の引数
(動詞V):は
(補語C):HASHやARRAYの要素/スライスではない
という意味になる。
2週間に一度、水曜日は、Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。
そのはずであったが、最近はCPANモジュールのインストールの方法を書いていて、しばらくご無沙汰になってしまった。
今回は
%s argument is not a HASH or ARRAY element or sliceを研究する。
これは、
(主語S):%s argument
(動詞V):is
(補語C):not a HASH or ARRAY element or slice
という第2文型の文で、
(主語S):%s の引数
(動詞V):は
(補語C):HASHやARRAYの要素/スライスではない
という意味になる。
%sの引数はHASHやARRAYの要素/スライスではないという訳になる。
これは、メッセージだけ眺めてみても意味が分からず、実際にプログラムで事故を起こすか、ラクダ本を眺めなければ分からない。
ハッシュや配列の要素、スライス以外のものにdelete関数を作用させたときに起こるメッセージである。
まず、エラーメッセージが発生しないプログラムを書く。
結果はこうなる。
配列要素のdeleteはPerl 5.6からの新機能で、要素を削除すると言っても値を未初期化にするだけで、配列要素の位置はズラされない。
よって2:のsayの前で、未定義の$arr[0]を表示しようとして「Use of uninitialized value...」という警告が出ている。
また2:のsayの中では、barの前に$arr[0]があった場所にヌル文字列が空白に挟まれて表示されている。
配列の要素数も5のままである。
2:と3:の間で配列スライス@arr[1..2]を削除している。
これでbarとbazが削除され、$arr[3]であるquxのみがヌル文字列3個の後に表示される。
削除した配列要素を表示しようとして警告が3つ出ている。
配列の要素数は5のままである。
3:と4:の間で配列要素$arr[4]を削除している。
quuxが削除されたわけだが、警告は3つしか表示されていない。
これは、delete関数を配列要素に適用したとき、末尾以外の要素の場合は要素が未初期化されるだけだが(配列スロットは残り、後続の要素の位置はズレないが)、末尾の要素に適用したときは、配列の長さが縮むという現象である。
要素数が4に縮んでいる。
4:と5:の間で現状の末尾要素である配列要素$arr[3]を削除している。
全部の要素が削除されたのだが、警告は表示されず、要素数はゼロになっている。
Perlの配列は勝手に伸び縮みする。
ここで戯れに
しかし、
6:以降のsayではハッシュのキーをソートし、joinで空白を挟んで表示している。
ハッシュ要素、ハッシュスライスを削除しているが、ちゃんと抹消されている。
さて、上のプログラムの末尾に変な行を書いてみる。
ちゃんと予想通りのエラーが表示された。
ハッシュや配列の要素、スライス以外のものにdelete関数を作用させたときに起こるメッセージである。
まず、エラーメッセージが発生しないプログラムを書く。
#! /usr/bin/perl上ではdelete関数を4回使って、配列の要素、配列のスライス、ハッシュの要素、ハッシュのスライスを削除して見ている。
#
# deleteExp.pl -- delete関数の実験
use 5.010;
use strict;
use warnings;
my @arr = qw(foo bar baz qux);
say "1: array: @arr";
delete $arr[0]; #配列の要素をdelete
say "2: array: @arr";
delete @arr[1..2]; #配列のスライスをdelete
say "3: array: @arr";
delete $arr[4]; #配列の末尾の要素をdelete
say "4: array: @arr";
my %hash = (
January => 1,
February => 2,
March => 3,
April => 4,
May => 5,
);
say "5: hash keys:", join(" ", sort keys %hash);
delete $hash{March}; #ハッシュの要素を削除
say "6: hash keys:", join(" ", sort keys %hash);
delete @hash{"January", "April"}; #ハッシュスライスを削除
say "7: hash keys:", join(" ", sort keys %hash);
結果はこうなる。
$ deleteExp.pl1:と2:の間で配列要素$arr[0]を削除している。
1: array: foo bar baz qux quux number:5
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 15.
2: array: bar baz qux quux number:5
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 19.
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 19.
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 19.
3: array: qux quux number:5
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 23.
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 23.
Use of uninitialized value in join or string at /Users/query1000/perl/deleteExp.pl line 23.
4: array: qux number:4
5: array: number:0
6: hash keys:April February January March May
7: hash keys:April February January May
8: hash keys:February May
$
配列要素のdeleteはPerl 5.6からの新機能で、要素を削除すると言っても値を未初期化にするだけで、配列要素の位置はズラされない。
よって2:のsayの前で、未定義の$arr[0]を表示しようとして「Use of uninitialized value...」という警告が出ている。
また2:のsayの中では、barの前に$arr[0]があった場所にヌル文字列が空白に挟まれて表示されている。
配列の要素数も5のままである。
2:と3:の間で配列スライス@arr[1..2]を削除している。
これでbarとbazが削除され、$arr[3]であるquxのみがヌル文字列3個の後に表示される。
削除した配列要素を表示しようとして警告が3つ出ている。
配列の要素数は5のままである。
3:と4:の間で配列要素$arr[4]を削除している。
quuxが削除されたわけだが、警告は3つしか表示されていない。
これは、delete関数を配列要素に適用したとき、末尾以外の要素の場合は要素が未初期化されるだけだが(配列スロットは残り、後続の要素の位置はズレないが)、末尾の要素に適用したときは、配列の長さが縮むという現象である。
要素数が4に縮んでいる。
4:と5:の間で現状の末尾要素である配列要素$arr[3]を削除している。
全部の要素が削除されたのだが、警告は表示されず、要素数はゼロになっている。
Perlの配列は勝手に伸び縮みする。
$arr[100] = "hey!";という式を書くと、$arr[0]から$arr[100]まで101個のスロットができ、101個目の配列要素$arr[100]に文字列「hey!」が入り、$arr[0]から$arr[99]まで未初期化の100個のスロットが出来る。
ここで戯れに
delete $arr[99];とやってみても、もともと未初期化の$arr[99]が未初期化状態にされるだけなので、何も起きない。
しかし、
delete $arr[100];とすると、唯一の初期化された配列要素である$arr[100]が削除されるので配列そのものが抹消される。
6:以降のsayではハッシュのキーをソートし、joinで空白を挟んで表示している。
ハッシュ要素、ハッシュスライスを削除しているが、ちゃんと抹消されている。
さて、上のプログラムの末尾に変な行を書いてみる。
my $scalar = 666;スカラー変数をdelete関数で消そうとしているのだが、どうなるだろうか。
delete $scalar;
$ deleteExp.plやったー。
delete argument is not a HASH or ARRAY element or slice at /Users/query1000/perl/deleteExp.pl line 49.
$
ちゃんと予想通りのエラーが表示された。