8

大きなチームによって「開発された」巨大なアプリケーションがあるとします;)。これは、誰かがデータ構造を深くチェックしすぎたときに発生する可能性のある災害の単純化されたモデルです。自動化を完全に、または範囲内で無効にすることができない場合、これを回避するにはどうすればよいですか? どうもありがとうございました :) !!!!

use strict; use warnings;use Data::Dumper;

my $some_ref = {akey=>{deeper=>1}};
print Dumper($some_ref );
if($some_ref->{deep}{doot} == 1){
    print 'too deep '.$/;
}

if($some_ref->{deep}){
    print 'Already in a deep doot'.$/;
}

print Dumper($some_ref );

これにより、次が出力されます。

$VAR1 = {
          'akey' => {
                      'deeper' => 1
                    }
        };
Use of uninitialized value in numeric eq (==) at autovivify_test.pl line 5.
Already in a deep doot
$VAR1 = {
          'deep' => {},
          'akey' => {
                      'deeper' => 1
                    }
        };

はい、警告があることは知っていますが、手遅れかもしれません。

私の hashref は、関連付けられた HASH を参照していると言うことが役に立ちます。

構造のより深い部分をチェックする優れた FETCH メソッドを実装すれば、問題を簡単に解決できるでしょうか?


Tie::StrictHashTie::Hash、およびperltieを見ました。これが私のソリューションの簡略版です:

#!/usr/bin/env perl;
#test_tie.pl

package StrictHash;
use strict; use warnings;
use Tie::Hash;
our @ISA = qw(Tie::StdHash);
use Carp;

sub TIEHASH {
    my $class = shift;
    my $hash = bless {@_}, $class;
    return $hash;
}
##========================================================================
## FETCH fails if applied to a member that doesn't exist.
##========================================================================
sub FETCH {
    my ($hash, $key) = @_;
    Carp::confess "key '$key' does not exist" unless exists $hash->{$key};
    return $hash->{$key};
}
##========================================================================
package main;
use strict;use warnings;use Data::Dumper;
#Imagine StrictHash is in ./StrictHash.pm
#use StrictHash;
my %hash;
tie %hash, 'StrictHash', akey => {deeper=>1} ;  

my $some_ref =\%hash;
print Dumper($some_ref );
if($some_ref->{deep}{doot} == 1){
    print 'too deep '.$/;
}

私が達成したことは、アプリ内の 1 か所だけをタッチすることです。これで、if($some_ref->{deep}{doot}) のようなすべての場所で、スタック トレースでダイが発生します。だから私はそれらを簡単に見つけて修正します。そして、この種の新しい文章は不可能です。Perl は大規模なアプリにも適しています。詳しく知る必要があります ;)。

皆さん、ありがとうございました!これが他の人にも役立つことを願っています。

4

5 に答える 5

22

比較的新しいのはautovivification、これを可能にするモジュールです。

no autovivification;

かなり簡単です。

于 2009-07-10T13:24:44.113 に答える
16

ハッシュの代わりにオブジェクトを使用するか ( Mooseを参照)、厳密に結び付けられたハッシュを使用することができます。または、本当に必要な場合は、警告をエラーに変えることができます。

use warnings NONFATAL => 'all', FATAL => 'uninitialized';
于 2009-04-26T09:29:42.110 に答える
9

Hash::Util (コア モジュール)の関数の 1 つを使用して、ハッシュをロックできます。

use Hash::Util qw( lock_keys unlock_keys );

my $some_ref = { akey => { deeper => 1 } };
lock_keys %$some_ref;

print "too deep" if $some_ref->{deep}{shit} == 1;

最後のステートメントで例外がスローされます。

Attempt to access disallowed key 'deep' in a restricted hash

もちろん、欠点は、例外を避けるためにハッシュ内のキーをチェックするときに非常に注意する必要があることです。つまり、" " の lof を使用しif exists ...てキーにアクセスする前にチェックします。

後で再度ハッシュにキーを追加する必要がある場合は、ロックを解除できます。

unlock_keys %$some_ref;
$some_ref->{foo} = 'bar'; # no exception
于 2009-04-26T10:22:02.127 に答える
3

@zoul に賛成を投じましたが、さらに一歩進める必要があります。

テストを書く

コードをテストでカバーする必要があり、それらのテストのいくつかを実行する必要があります

use warnings FATAL => 'uninitialized';

テストケース自体で宣言されています。開発者が事前に適切にチェックしていないという懸念に対処する唯一の方法です。コードがテストされていることを確認してください。

さらに一歩進んで、 Devel::Coverの下で簡単にテストを実行して、カバレッジ レポートを取得できるようにします。

cover -delete
PERL5OPT='-MDevel::Cover' prove -l 
cover -report Html_basic 

そして、コードの行とステートメントがテストによって実行されていることを確認します。そうしないと、これらの警告を致命的にすると、後で予期しないときにコードが停止するだけです。

于 2009-04-26T10:42:26.070 に答える