Automatically call hash values that are subroutine references

前端 未结 7 2061
孤街浪徒
孤街浪徒 2021-01-06 07:02

I have a hash with a few values that are not scalar data but rather anonymous subroutines that return scalar data. I want to make this completely transparent to the part of

7条回答
  •  囚心锁ツ
    2021-01-06 07:29

    There's a feature called "magic" that allows code to be called when variables are accessed.

    Adding magic to a variable greatly slows down access to that variable, but some are more expensive than others.

    • There's no need to make access to every element of the hash magical, just some values.
    • tie is an more expensive form of magic, and it's not needed here.

    As such, the most efficient solution is the following:

    use Time::HiRes     qw( time );
    use Variable::Magic qw( cast wizard );
    
    {
       my $wiz = wizard(
          data => sub { my $code = $_[1]; $code },
          get => sub { ${ $_[0] } = $_[1]->(); },
       );
    
       sub make_evaluator { cast($_[0], $wiz, $_[1]) }
    }
    
    my %hash;
    $hash{key1} = 'value1';
    make_evaluator($hash{key2}, sub { 'value2@'.time });
    
    print("$hash{$_}\n") for qw( key1 key2 key2 );
    

    Output:

    value1
    value2@1462548850.76715
    value2@1462548850.76721
    

    Other examples:

    my %hash; make_evaluator($hash{key}, sub { ... });
    my $hash; make_evaluator($hash->{$key}, sub { ... });
    
    my $x; make_evaluator($x, sub { ... });
    make_evaluator(my $x, sub { ... });
    
    make_evaluator(..., sub { ... });
    make_evaluator(..., \&some_sub);
    

    You can also "fix up" an existing hash. In your hash-of-hashes scenario,

    my $hoh = {
       { 
          key1 => 'value1',
          key2 => sub { ... },
          ...
       },
       ...
    );
    
    for my $h (values(%$hoh)) {
       for my $v (values(%$h)) {
          if (ref($v) eq 'CODE') {
             make_evaluator($v, $v);
          }
       }
    }
    

提交回复
热议问题