- ベストアンサー
サブルーチンの引数の、呼び出し側の呼称を得る
サブルーチンの呼び出し、例えば sr($p); という呼び出しがあった場合、サブルーチンsb()の中で、引数は@_として扱われて、 $p の値などは $_ で知ることが出来ます。 それではサブルーチンsb()の方から、 $_ が呼び出し側で何と呼ばれているか知ることは出来るのでしょうか? つまり、この場合、$_は呼び出し側で $p と呼ばれているわけですが、この呼称をサブルーチン側で知ることは出来るでしょうか。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
そもそもサブルーチン内で 呼び出しもとの実引数の「変数名」を 「本当に必要」な状況そのものを想像できません. 質問の文面とものの言い方から初心者さんではないようなので もしかするとものすごい状況にいるのかもしれませんが・・・ そうすると,以下に書くようなことは とっくに検討済みの可能性もありますね サブルーチンの中で呼び出しもとの変数をいじりたいのであれば $a=10; sub { $_[0]++ }->($a); print $a; とかすれば,可能ですね(Perlはcall by referenceだから). もっともこれは,具体的な値そのものを渡せばエラーになります. ただ「参照渡し」なので,$_[0]と呼び出し元の変数の 実体は同じ,つまり,\$_[0]と\$aは同じだから \$_[0]と同じ値を持つものをシンボルテーブルから 無理やり探し出すことは可能だと思われます. $a=10; sub {foreach $val (values %main::){ *glob=$val; $temp=$val; if (\$_[0]==\$glob) { $temp=~s/\*main:://; print "argument: \$$temp\n" } } } ->($a); こんな感じ. ただし,シンボルテーブルを読んでるわけだから, レキシカルな変数は相手にできませんし, この例だと引数はスカラであることが前提です. けど,リファレンスを渡してあげれば,細工すれば スカラ以外でも処理できるでしょう. けど,シンボルテーブルで遊ぶ以外の意味はなさげです. なお,これは具体的な値を渡すと何も出力されませんし, レキシカルな変数を相手にするにはどうすればいいでしょうね? 「レキシカルな変数のシンボルテーブル」? BモジュールとかPadWalkwerとかの「黒魔術の世界」に 浸ればできるのかもしれませんが,私レベルでは分かりません. #use strictとの両立方法・・・わかりません. いっそのこと,引数そのものに もっと細かい情報を持たせるというのもありかもしれません. Scalar::Utilのdualvar関数を使って 自分自身の情報を変数にもたせるというのもありかも. もしかするとattributeを利用してもいいのかも #この段落の内容は実験してない想像にすぎません. そして,「変数名」を取得して, サブルーチン内で「ソフトリファレンス」したいのでしょうか? つまり, $fred = 23; $varname = "fred"; ++$$varname; というようなことをしたいということでしょうか? これは,perldoc perfaq7で How can I use a variable as a variable name? の項目をよめば 「Beginners often think」で 「very bad idea」だと詳細な説明があります. こんなことは先刻承知かもしれませんが. まあ,なにはともかく >人間的にみれば第1引数に第2引数の情報は全て入っているのに これには私も同意しませんけどねえ. 仮に「人間的に入ってても」そもそもPerlは人間じゃないですし, すべての情報が入っててもそれが渡されるわけではないですな. それと >このコーディングは私の無知を象徴することになってしまうので、 無知をさらけ出すよりも メンテナンスや拡張が困難なコードを残すほうが 私はいやです. #というか・・・Perlじゃないけど #メンテナンス困難なコードのバグ取りを #よくさせられるから・・・ メンテナンス不可の簡潔なコードよりも メンテナンスが楽な可読性の高い冗長・饒舌なコードのほうが ずっといいとおもうのは私だけではないと思います.
その他の回答 (4)
- Tacosan
- ベストアンサー率23% (3656/15482)
いちおう #3 の時点で「シンボルテーブルを読む」のは想定したんですけど, *b = \$a; とされてしまうと「シンボルテーブルを読んでも $a と $b を区別することができない」のであきらめました>#4. っつ~か, この状況で $a と $b を区別する意味が私にはわかりませんが. そういう意味で「変数名が必要な状況」がわからないというのは同意. ALGOL ならよかったのにね.
- Tacosan
- ベストアンサー率23% (3656/15482)
では結論だけ: 1つの引数だけで知る方法はありません. リファレンスだろうとなんだろうと, できないものはできません. 「人間的にみれば第1引数に第2引数の情報は全て入っている」というのが既に間違っているので....
- Tacosan
- ベストアンサー率23% (3656/15482)
sr(7); という呼び出しの場合には何を知ればよいということになるのでしょうか? そして sr(4+3); のときは?
補足
今問題にしているのは、変数を引数にした場合に、その変数の値ではなく呼称を得ることが出来るかという問題であって、値そのものを引数にした場合に、その呼称をどう扱うべきかは、次の問題です。そういう補足を求めてこられるということは、Tacosanさんの中で、当初の題意は解決済みということですが、それはどのような方法なのでしょうか。 引数に連想配列や配列をそのまま指定した場合、サブルーチン側ではそれは全て @_ として扱われるから、引き渡された変数が連想配列であるか配列であるか分からなくなります。つまり引数の頭に「@」が付いているのか、「%」が付いているのかすら、サブルーチン側では判別できないということかと。 でもリファレンスで送ればこの問題は解決するわけです。さらにサブルーチンの引数を一つ増やして、例えば sr(\@a,'a') のようにしてあげればサブルーチン側で、引数が呼び出し側で「@a」と呼ばれていたのだと理解できます。 ただ人間的にみれば第1引数に第2引数の情報は全て入っているのに、あらためて第2引数でその情報を渡すというのは馬鹿らしく、もし第1引数だけで題意が適うならば、このコーディングは私の無知を象徴することになってしまうので、だから念のために、皆さんにご教授をお願いしている次第です。 やはりこれが最良の方法なのでしょうか。
- kirikirkaz
- ベストアンサー率60% (21/35)
> サブルーチンの呼び出し、例えば > sr($p); > という呼び出しがあった場合、サブルーチンsb()の中で、引数は@_として扱われて、 sb?srじゃないんですか? > $p > の値などは > $_ > で知ることが出来ます。 $_?$_[0]の間違いじゃないですか?
補足
その通りです。 typo、気をつけます。
お礼
ご教授、ありがとうございます。 前回の私の態度には問題があったかもしれません。お詫びします。アラシのような行為(人を小馬鹿にしたような文面で、分かり切ったtypoの指摘をしたり関係ない質問をするけど、でも実質的な話は進まない。)にムカついていました。 今回はデバッグツールを自作しようと思った次第です。 プログラム中にデバッグ関数を書きいれて、その位置における変数の値を知るに際して、その関数がファイル名、行番号、変数名を自動で記述してくれたら助かると思いました。 ご教授いただいだPadWalkerモジュールを用いました。 peek_my()のrefをとってmy変数かour変数かを調べる。 our変数だったらpeek_our変数でオブジェクトを生成し直す。 生成したオブジェクトに対して、連想配列、配列、スカラーに場合分けして、値を書きだす。 この場合、値や式を引数に取れません。リファレンスも無理だと思います。そういったところが使い勝手が悪いですが、そういう特殊用途向けにはコメントを手動で記述する関数がありますので、そちらと併用しようと思います。 助かりました。 どうもありがとうございます。