5

Michael Carman のコメントに照らして、質問を書き直すことにしました。この編集の前に 11 のコメントが表示されていることに注意してください。また、私が求めていることを明確にする方法で質問を書いていないというマイケルの観察に信憑性を与えてください。


質問:モジュールをインポートするだけで、strict に関して持つ特別なステータスを偽装するための標準的な (または最もクリーンな) 方法は何ですか?$a$b

まず最初にいくつかのセットアップ。以下の作品:

#!/bin/perl
use strict;
print "\$a=$a\n";
print "\$b=$b\n";

もう 1 行追加すると、次のようになります。

print "\$c=$c\n";

コンパイル時にエラーが発生します。これは、見事な印刷コードが実行されないことを意味します。

コメントアウトすると正常にuse strict;動作します。制限の外では、$a主に、それらの名前と比較する 2 つの値を渡すという点$bで特別です。sort

my @reverse_order = sort { $b <=> $a } @unsorted;

したがって、 と の主な機能上の違いは$a$bたとえ Perl が「それらの名前を知っている」としても、ソートするとき、またはList::Utilのいくつかの関数を使用するときに、これを知っている方がよいということです。

strict を使用して、まったく新しい方法で特殊変数になる$a場合のみです。$bそれらは、宣言されていないことを訴えることなく、厳密に渡される唯一の変数です。

:さて、私は厳密が好きですが、TIMTOWTDI (それを行うには複数の方法があります) が Perl のルール #1 である場合、これはあまり TIMTOWDI ではないことに気づきました。それはそれを言い、$a特別$bであり、それだけです。変数を使用したい場合は、宣言する必要はありませ$a$b。を追加して 3 つの変数が必要な場合$c、突然、まったく別の方法があります。

ハッシュを操作$kする際に$v、より理にかなっている可能性があることを気にしないでください。

my %starts_upper_1_to_25 
    = skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;`

今、私は厳格なものを使用しています。しかし、私はただ、最もコンパクトな構文で見えるようにしたい$kと思っています。そして、私はそれが単に見えるようにしたい$vskim

use Hash::Helper qw<skim>;

私はこの質問を、黒魔術の方法を知りたくて尋ねているのではありません。以下の私の「答え」は、危険な Perl を十分に知っていることを知らせてくれるはずです。厳密に他の変数を受け入れる方法があるかどうか、または最もクリーンな解決策は何かを尋ねています。答えはノーかもしれません。そうであれば、TIMTOWTDI とは思えません。

4

13 に答える 13

7

他の人は、「vars」と「our」を使用する方法について言及しました- $a と $b はソートルーチンによって内部的に使用されるため、特殊なケースであることを追加したかっただけです。strict.pm ドキュメントからのメモは次のとおりです。

Because of their special use by sort(), the variables $a and $b are 
exempted from this check.
于 2008-09-29T20:34:08.147 に答える
4

私が正しく理解していれば、あなたが望むものは次のとおりです。

use vars qw($a $b); # Pre-5.6

また

our ($a, $b); # 5.6 +

ここでそれについて読むことができます。

于 2008-09-29T20:25:09.090 に答える
4

$a と $b は、コア言語の一部であるため、特別です。独自の同様の特殊変数を作成できないことを反 TIMTOWTDI だと言う理由は理解できますが、「print」または「」の順序で新しい基本コマンドを作成できないことに他なりません。選別'。(モジュールでサブルーチンを定義することはできますが、それはそれらを真のキーワードにはしません。それは、'our $k' を使用するのと同じです。あなたが言っているように、$k を $a のように十分なものにはしないと思われます。)

名前を他の誰かの名前空間にプッシュする場合、これはエクスポーターの実際の例になるはずです:

package SpecialK;

use strict;

use base 'Exporter';
BEGIN {
  our @EXPORT = qw( $k );
}

our $k;

1;

これを SpecialK.pm に保存し、'use SpecialK' で $k を利用できるようにします。「my」変数ではなく、「our」変数のみをエクスポートできることに注意してください。

于 2008-09-29T22:26:49.563 に答える
2

Perl 5.6 以降では、以下を使用できます。

our ($k, $v);

または、古い「use vars」に固執することもできます。

use vars qw($k $v);

または、「my」に固執することもできます。たとえば、次のようになります。

my %hash;
my ($k,$v);
while (<>) {
  /^KEY=(.*)/ and $k = $1 and next;
  /^VALUE=(.*)/ and $v = $1;
  $hash{$k} = $v;
  print "$k $v\n";
}

__END__
KEY=a
VALUE=1
KEY=b
VALUE=2

上記の例では、グローバルな $v を作成する必要はありませんが、うまくいけば、アイデアが得られることを願っています (一方、$k は while ブロックの外側にスコープを設定する必要があります)。

または、完全修飾変数名を使用できます。

$main::k="foo";
$main::v="bar";
%main::hash{$k}=$v;
于 2008-09-29T20:35:48.800 に答える
2

私があなたの質問を理解している場合は、ユーザーの名前空間で変数を宣言し (そうする必要はありません)、コールバックで自動的にローカライズされるモジュールを作成する必要があります。そうですか?

これを行うには、グローバルを宣言してエクスポートします。(ただし、一般的に、要求されずにエクスポートすることは悪い形式と見なされていることに注意してください。)

package Foo;
use strict;
use warnings;

require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(*k *v hashmap);
our ($k, $v);

sub hashmap(&\%) {
    my $code = shift;
    my $hash = shift;

    while (local ($k, $v) = each %$hash) {
        $code->();
    }
}

注:エクスポートは と で*kあり、 と ではあり*vません。タイプグロブ全体をエクスポートしないと、ユーザーのパッケージからinが正しく機能しません。これの副作用は、 andのさまざまな形式( 、など) がすべて宣言され、エイリアス化されることです。これの完全な説明については、Symbol Tables in perlmodを参照してください。$k$vlocalhashmapkv%k@v

次に、スクリプトで:

use Foo; # exports $k and $v

my %h = (a => 1, b => 2, c => 3);

hashmap { print "$k => $v\n" } %h;

__END__
c => 3
a => 1
b => 2
于 2008-09-30T16:00:07.563 に答える
1

誰かがこれを明確にしたかどうかはわかりませんが、strictは$aと$bをホワイトリストに登録しません。これは、これらが独自のルーチンで使用するのに非常に便利な変数名だからです。$aと$bは、並べ替え演算子にとって特別な意味を持ちます。これは、そのようなソートルーチン内の観点からは良いですが、外部からは一種の悪い設計です。:)もしそうなら、他の文脈で$aと$bを使うべきではありません。

于 2008-09-30T13:04:59.280 に答える
1

次のような魔法をやりたいようですList::MoreUtils

use strict;
my @a = (1, 2);
my @b = (3, 4);
my @x = pairwise { $a + $b } @a, @b;

ソースpairwiseのサブList::MoreUtils見るだけにすることをお勧めします。巧妙なシンボルテーブルをいじって、呼び出し元の名前空間に挿入$a$b、サブボディ内にローカライズします。おもう。

于 2008-09-29T22:39:45.507 に答える
1

これは私のために働いた:

package Special;
use base qw<Exporter>;
# use staging; -> commented out, my module for development
our $c;

our @EXPORT = qw<manip_c>;

sub import { 
    *{caller().'::c'} = *c;
    my $import_sub    = Exporter->can( 'import' );
    goto &$import_sub;
 } 

また、$cもstrictを通過します。

package main;
use feature 'say';
use strict;
use Special;
use strict;
say "In main: \$c=$c";

manip_c( 'f', sub {
    say "In anon sub: \$c=$c\n"; # In anon sub: $c=f
});

say "In main: \$c=$c";

ええ、モジュールを「use strict」で囲んだのはちょっとばかげていますが、内部はわかりません。これにより、潜在的なシーケンスの問題が解決されます。

于 2008-09-29T22:40:17.063 に答える
1

$aそして$b単なるグローバル変数です。$kandを宣言するだけで、同様の効果を得ることができます$v

use strict;
our ($k, $v);

(この場合$k、 and$vはグローバル変数ではなく、パッケージ変数のレキシカル スコープ エイリアスです。しかし、境界を越えなければ、同様に十分です。)

于 2008-09-29T20:24:41.993 に答える
1

ただし、 $a と $b は通常の変数ではなく、レキシカル宣言や明示的なエクスポート、シンボル テーブルのいじりによって簡単に複製することはできません。たとえば、デバッガーをシェルとして使用する場合:

  DB<1> @foo = sort { $b cmp $a } qw(foo bar baz wibble);

  DB<2> x @foo
0  'wibble'
1  'foo'
2  'baz'
3  'bar'
 DB<3> x $a
0  undef
  DB<4> x $b
0  undef

$a と $b は、sort() に渡されたブロック内にのみ存在し、その後は存在しません。さらに、sort へのさらなる呼び出しがそれらを踏まないようにスコープを持っています。

それを複製するには、おそらくソースフィルターをいじり始めて、好みの表記法に変える必要があります

my %starts_upper_1_to_25 
    = skim { $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <= 25 ) } %my_hash
;

効果的に

my %starts_upper_1_to_25
    = map { my $k = $_; my $v = $my_hash{$v};
            $k =~ m/^\p{IsUpper}/ && ( 1 <= $v && $v <=> 25 ) } keys %my_hash
;

$a と $b は $_ と @_ と同じくらい特別で、Perl 5 でこれらの名前を簡単に変更する方法はありませんが、Perl 6 では特定のキーワードを使用して実際にこれを修正します。「与えられた」というのは検索するのに不適切な用語ですが、http://dev.perl.org/perl6/doc/design/syn/S03.htmlから始めるのがよいでしょう。

于 2008-10-01T00:26:18.533 に答える
1

これはあなたの後ですか?.....

use strict;
use warnings;
use feature qw/say/;

sub hash_baz (&@) {
    my $code   = shift;  
    my $caller = caller;
    my %hash   = (); 
    use vars qw($k $v);

    no strict 'refs';
    local *{ $caller . '::k' } = \my $k;
    local *{ $caller . '::v' } = \my $v;

    while ( @_ ) {
        $k = shift;
        $v = shift;
        $hash{ $k } = $code->() || $v;
    }

    return %hash;
}

my %hash = ( 
    blue_cat   => 'blue', 
    purple_dog => 'purple', 
    ginger_cat => 'ginger', 
    purple_cat => 'purple' );

my %new_hash = hash_baz { uc $v if $k =~ m/purple/ } %hash;

say "@{[ %new_hash ]}";

# =>  purple_dog PURPLE ginger_cat ginger purple_cat PURPLE blue_cat blue
于 2008-09-29T23:36:50.220 に答える
0

モジュールは、エクスポートの使用は実際にはと変わらないことを示唆しましたuse vars。ただし、use vars$aのような変数を使用する各パッケージで実行する必要があります。そしてour()、それぞれの外部スコープで実行する必要があります。

$$-prototyped subを使用することで、ソートにも$aと$bの使用を回避できることに注意してください。

sub lccmp($$) { lc($_[0]) cmp lc($_[1]) }
print join ' ', sort lccmp
   qw/I met this guy and he looked like he might have been a hat-check clerk/;

これは、sort呼び出しとは異なるパッケージで比較ルーチンを使用する場合に不可欠です。

于 2008-10-02T06:44:27.040 に答える
-3

編集-これは実際には正しくありません。コメントを参照してください。他の人に私の間違いから学ぶ機会を与えるためにここに置いておきます:)


ああ、あなたはモジュールがCALLERの名前空間で$kと$vを宣言する方法があるかどうか尋ねていますか?Exporterを使用して、変数を呼び出し元にプッシュできます。

use strict;

package Test; 
use Exporter;

my @ISA = qw/Exporter/; 
my $c = 3; 
my @EXPORT = qw/$c/; 

package main; 
print $c;
于 2008-09-29T20:53:58.927 に答える