0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

パッケージ変数(配列・連想配列)へのもう一つの値の入れかた

Last updated at Posted at 2024-06-28

凄く今更。
Perl で新規スクリプトを書く予定もないし、こんなコードを使う気もない。
ただ、記憶の奥底に沈めた訳分らんコードが目についた以上、放置するのは奥歯にものが
挟まったみたいで嫌だったので。

本稿のプログラムは全て use strict; use warnings; の下、動作します。


[2024/07/08]

本稿は、結局は型グロブを利用してました。ってだけの記事です。

なので、本稿を読むより、型グロブの本格的な解説記事を読まれる方が良いかと思います。


発端

% perl -le '0->[0] = 100; print 0->[0];' -Mstrict -Mwarnings
100

え、、、何これ。1

左辺値が裸の 0 で始まってるのに、怒られてないよ?
何でリファレンスなの?
B::Deparse したら $0[0] のことだって。何でこう書けるの?


利用している機能

配列・連想配列の型グロブ(*Foo::Bar)利用時に、何にアクセスするか自明の場合は * を省略出来る模様。その代りクォーテーションで括る必要がある。 2

型グロブで、%main::h へ値の代入。print 時には ->{} でハッシュにアクセスしているのは明白

% perl -le '*main::h = { 10, 11} ; print *main::h->{10};'
11

なので、以下の様に記載出来る。

% perl -le '"main::h"->{10} = 11 ; print "main::h"->{10};'
11

時々、CPAN モジュールの中とかで見られる書き方ではあるけど、普通は使わない。


型グロブでのパッケージ名の省略

型グロブでは、メインパッケージの場合、パッケージ名の省略が可能

% perl -le '*h = { 10, 11} ; print *h->{10};' -Mstrict -Mwarnings
11

定義済みの変数への適用

上記の機能は、当然、 定義済みの変数(配列・連想配列)への代入にも使える。

  1. Perl の定義済みの変数は、main パッケージのパッケージ変数である
  2. $\d+, @\d+, %\d+ は定義済みのリストには載っていないものの、実質定義済みの変数として扱われる

従って 1. については以下の様にコードが書ける。

%ENV に値を追加したり

% perl -le '"ENV"->{TEST} = "test"; print Dumper \%ENV;' -MData::Dumper
$VAR1 = {
        (前略)
        'TEST' => 'test',
        (後略)
    };

$ARGV[0] を変更したり

% cat test.txt
hoge
% perl -lpe 'BEGIN{ "ARGV"->[0] = "test.txt" }'
hoge

で、2.。

perl では変数名として、シジルの直後に数字のみで構成された文字列が使用可能である。3

定義済みとして扱われているので、当然変数名宣言無しでも use strict; use warnings; が通る。

% perl -le '@0 = (100); print $0[0];'

と言うことで、型グロブで記載すると

# perl -le '*0 = [ 100 ]; print *0->[0];'
% perl -le '*0->[0] = 100; print *0->[0];'
100

で、* を省略

% perl -le '0->[0] = 100; print 0->[0];'
100

"0"->[0] じゃなくて 0->[0] で機能するのは、Perl のご都合主義の成せる技。(まあ、単に数値だから。)

% perl -MDevel::Peek -e '0->[0] = 100; Dump(@0);'
SV = PVAV(0x12500d2f0) at 0x1250173a8
  REFCNT = 1
  FLAGS = ()
  ARRAY = 0x124e0b3e0
  FILL = 0
  MAX = 3
  FLAGS = (REAL)
  Elt No. 0
  SV = IV(0x12500bc00) at 0x12500bc10
    REFCNT = 1
    FLAGS = (IOK,pIOK)
    IV = 100                          # <= Integer 100 が入ってますよ

改めて調べようとすると4、Google 先生はボケちゃってるし、(無料版) ChatGPT 先生は頓珍漢な答えしかしてくれないし、質問サイトにも Perl 古参の方々は居なさそうだし、有用なサイトは沈んでるか消えてるし5、 寂しいものだ。


BTW

あ、B::Deparse の穴みっけ

% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;'
10
100

% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;' -MO=Deparse
BEGIN { $/ = "\n"; $\ = "\n"; }
$0[0] = 100;
package HOGE;
$0[0] = 10;
print $0[0];
print $0[0];
'???';
-e syntax OK

% perl -le '0->[0] = 100 ; package HOGE; "HOGE::0"->[0] = 10; print "HOGE::0"->[0]; print 0->[0]; 1;' -MO=Deparse | grep -v '???' | perl
-e syntax OK
10
10

つか、定義済み変数の"暗黙の main パッケージ変数である"って挙動に対応していないのかな、、、でもないね。

% perl -le '"ENV"->{"T"} = "test" ; package HOGE; "HOGE::ENV"->{"T"} = "HOGE"; print "HOGE::ENV"->{"T"}; print "ENV"->{"T"}; 1;'  -MO=Deparse
BEGIN { $/ = "\n"; $\ = "\n"; }
$ENV{'T'} = 'test';
package HOGE;
$HOGE::ENV{'T'} = 'HOGE';
print $HOGE::ENV{'T'};
print $ENV{'T'};
'???';
-e syntax OK

  1. どこぞのページで見付けたコードから。古いページだし、解説もされてないし、敢てリンクしません。

  2. 但し、perldoc 内でそれらしき説明には行きあたっていない

  3. perldoc perldata の変数名の項の下部参照。ちなみにスカラについては、$0perldoc perlvar に記載の定義済み変数、記載はないものの $1 からの 0 埋めされていない数値は、正規表現マッチ結果の入った変数として使われる。それ以外 - 0 が先頭のもの($010) など - は使われていない。

  4. 自分自身も型グロブが思い当たらず、ずいぶん遠まわりしてしまった。ここまで、ボケるものか

  5. KENT WEB が生き残ってるのに驚愕した! Copyright が 2023 だから、少なくとも去年まではメンテされているの?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?