代码之家  ›  专栏  ›  技术社区  ›  Беров

如何在Perl中禁用自动激活?

  •  8
  • Беров  · 技术社区  · 15 年前

    假设您有一个大团队“开发”了一个巨大的应用程序。 这里是一个简化的潜在灾难模型,当有人对数据结构进行过深的检查时,可能会发生这种情况。 如果不能完全或在范围内禁用自动振动,如何解决这个问题? 非常感谢:)!!!!!

    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可能会有所帮助。

    如果我实现一个好的获取方法来检查结构中更深层的检查,我会很容易地解决我的问题吗?


    我看着 Tie::StrictHash , Tie::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 '.$/;
    }
    

    我所取得的成就是只触摸应用程序中的一个位置。 现在,所有的地方,比如if($some-ref->deep doot),都会导致带有堆栈跟踪的死亡。 所以我很容易找到它们并改正它们。 这样的新作品是不可能的。 Perl也适用于大型应用程序,您只需了解更多;)。

    谢谢大家! 我希望这也能帮助别人。

    5 回复  |  直到 6 年前
        1
  •  15
  •   Community Michael Schmitz    11 年前

    您可能希望使用对象而不是哈希(请参见 Moose )或使用 strict tied hash . 或者,如果您真的想:

    use warnings NONFATAL => 'all', FATAL => 'uninitialized';
    
        2
  •  21
  •   Richlv    6 年前

    相对较新的是 autovivification 模块,允许您执行此操作:

    no autovivification;
    

    很简单。

        3
  •  9
  •   Dmitry Lobanov    15 年前

    可以使用以下函数之一锁定哈希: Hash::Util (核心模块)。

    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
    
        4
  •  3
  •   Community Michael Schmitz    7 年前

    我投票赞成 @zoul 但是你应该更进一步。

    写测试

    您应该将代码包含在测试中,并且应该使用

    use warnings FATAL => 'uninitialized';
    

    在测试用例本身中声明。这是解决开发人员未提前正确检查问题的唯一方法。确保测试了它们的代码。

    再往前走一步,让你的测试在 Devel::Cover 获取覆盖率报告。

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

    然后检查代码行和测试正在执行的语句,否则使这些警告致命,只会使代码在以后的意外时间死亡。

        5
  •  2
  •   HoldOffHunger Lux    6 年前

    另一个选择是使用 Data::Diver 访问您的数据结构。

    if( 1 == Dive($some_ref, qw/ deep structures are not autovivified now / )) {
        Do_Stuff();
    }