8

私は次のようなPerlコードを持っています:

# -- start --

my $res;

# run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

# -- stop --

クエリ結果を反復処理する前に設定されることはありませ$resんが、コードは正常に実行されます。

各値の前にprintステートメントを置くと、どちらの場合も空白になりますが、増分が適用された後にprintステートメントが来ると、組織にあるIPv6リソースの数に応じて>=1の値が得られます。

私の質問は、これをPerlの初期化されていないハッシュキーの値が自動的にゼロになることを意味すると解釈しますか?

初心者の質問として出くわした場合は申し訳ありませんが、私はそのような構成に精通していません。つまり$hashref->{foo}->{bar}++ 、値がまだ明示的に割り当てられていない場合$hashref->{foo}->{bar}です。前もって感謝します!

4

4 に答える 4

26

値は自動的にゼロにはなりません。値は最初は未定義です。ただし、数値のように扱う場合 (たとえば、それに適用++する場合)、Perl はそれをゼロのように扱います。これを文字列のように扱う (たとえば、それに適用.する) と、Perl はそれを空の文字列のように扱います。

からperldoc perlsyn、「宣言」の下に:

Perl で宣言する必要があるのは、レポート形式とサブルーチンだけです (場合によってはサブルーチンでさえありません)。変数は、「undef」以外の定義済みの値が割り当てられるまで、未定義の値 (「undef」) を保持します。数値として使用される場合、「undef」は 0 として扱われます。文字列として使用すると、空の文字列 "" として扱われます。割り当てられていない参照として使用すると、エラーとして扱われます。

于 2009-05-01T14:28:49.477 に答える
5

Telemachus の投稿を詳しく説明すると、初期化されていない値は未定義になります。構造の深い部分は自動活性化されます。これは、データ構造が自動的に作成される便利な機能です。Autovivification は、必要な場合には優れていますが、防止したい場合は面倒な場合があります。autovivification を理解するための多くのチュートリアル、記事、投稿がネット上にあります。

したがって、未定義の$refand$ref->{ipv6}{pa}{'foo'}++が与え$refられた場合、次の値が割り当てられます。

$ref = { 
     ipv6 => { 
          pa => { 
              foo => undef
          }
     }
};

undef は 0 に numify されるため、undef はインクリメントされ、1 である 0++ が得られますref->{ipv6}{pa}{'foo'} == 1

警告を有効にしている場合 (そうuse warnings;ですよね?)、これらの未定義の値を操作すると、「初期化されていない値」という警告が表示されます。初期化された値をインクリメントすることが望ましい動作である場合は、コードの限られた部分で目的の警告グループをオフにすることができます。

use strict;
use warnings;
my $res;

// run query to fetch IPv6 resources
while( my $row = $org_ip6_res->fetchrow_arrayref )
{   no warnings 'uninitialized';
    if( $row->[4] =~ /PA/ ) {
        $res->{ipv6}{pa}{$row->[2]}++;
    } elsif( $row->[4] eq 'PI' ) {
        $res->{ipv6}{pi}{$row->[2]}++;
    }
}

警告階層はperllexwarnにあります。

于 2009-05-01T15:11:35.053 に答える
4

基本的には定義されていませんが、インクリメントするとゼロであるかのように扱われます。

Perl の用語は「autovivified」です。

おそらくやりたいことは、exists キーワードを使用することです。

$res->{ipv6}{pa}{$row->[2]}++ if exists($res->{ipv6}{pa}{$row->[2]});
于 2009-05-01T14:34:44.423 に答える
2

初期化されていないハッシュキーのようなものはありません。初期化されない可能性があるのは、特定のキーの値です。ハッシュ値は単なるスカラー値です。のような変数と同じ$fooです。

あなたの例では、相互作用するいくつかの異なるPerl機能があります。

最初$resは未定義です(つまり、値がありますundef)。初期化されていない値をハッシュ参照として使用すると(のように$res->{ipv6}...)、Perlはそれを1つとして「自動活性化」します。つまり、Perlは匿名ハッシュを作成し、の値をundef新しいハッシュへの参照に置き換えます。このプロセスは、結果の値を参照として使用するたびに(サイレントに)繰り返されます。

最終的に$res->{ipv6}{pa}{$row->[2]}は、未定義のへの道を自動活性化します。これは、のような単なるスカラー値であることを忘れないでください$foo。振る舞いは言うのと同じです

my $foo;
$foo++;

未定義の値を使用すると、Perlは特別なことを行います。それらを数値として使用する場合、Perlはそれらを0に変換します。それらを文字列として使用する場合、Perlはそれらを''(空の文字列)に変換します。ほとんどの場合、警告を有効にすると(これを行う必要があります)、「初期化されていない値を使用しています...」という警告が表示されます。ただし、自動インクリメント演算子(++)は特殊なケースです。便宜上、値をインクリメントundefする前に、値をからにサイレントに変換します。0

于 2009-05-01T18:03:27.667 に答える