Perl Hash ссылается на значения хеша внутри того же хеша

Мое требование, как показано ниже. Внутри того же хеша значения ключей зависят от другого значения ключа, как показано ниже

my %test;

$test{map}{a} = 32;
$test{map}{b} = $test{map}{a}+10;
$test{ref}{r} = $test{map}{b};

Итак, когда я делаю печать Dumper(\%test); я получил

$VAR1 = {
          'ref' => {
                     'r' => 42
                   },
          'map' => {
                     'a' => 32,
                     'b' => 42
                   }
        };

Если я изменю значение хеша

$test{map}{a} = 42

я получил

$VAR1 = {
          'ref' => {
                     'r' => 42
                   },
          'map' => {
                     'a' => 42,
                     'b' => 42
                   }
        };

Вместо этого у меня должен быть обновленный тест hash %, как показано ниже

$VAR1 = {
          'ref' => {
                     'r' => 52
                   },
          'map' => {
                     'a' => 42,
                     'b' => 52
                   }
        };

Как добиться вышеуказанного результата? Любая помощь высоко ценится

2 ответа

Решение

Семантика написанного вами кода не та, которую вы себе представляли. Особенно:

$test{map}{b} = $test{map}{a}+10;
$test{ref}{r} = $test{map}{b};

Это не - как я думаю, вы себе представляли - "правила" для получения значения $test{map}{b} а также $test{map}{b} каждый раз, когда кто-то их читает, но инструкции, которые при выполнении изменяют значение, связанное с ключами b а также r, И это все.

Если вы хотите, чтобы элементы в вашем хэше были динамическими, одним из возможных подходов может быть использование ссылок на подпрограммы, а также механизм для оценки этих правил, когда пользователь запрашивает значения. Но имейте в виду, что это может быть сложно: например, как насчет циклических ссылок? Или правила, которые ссылаются на другие правила, в качестве ключа r в твоем примере?

В любом случае, вот код для доказательства концепции:

use strict;
use warnings;
use v5.10;

my %test;

$test{map}{a} = 32;
$test{map}{b} = sub { evaluate( $test{map}{a} ) + 10 };
$test{ref}{r} = sub { evaluate( $test{map}{b} ) };

sub evaluate {
  my $expr = shift;
  if ( ref $expr eq 'CODE' ) {
    # We need to execute the procedure indicated 
    # to obtain a value
    return $expr->();
  }
  else {
    # Otherwise, we just return what we found associated to the key
    return $expr;
  }
}

say evaluate( $test{ map }{ a } ); # 32
say evaluate( $test{ map }{ b } ); # 42
say evaluate( $test{ ref }{ r } ); # 42

$test{map}{a} = 42;

say evaluate( $test{ map }{ a } ); # 42
say evaluate( $test{ map }{ b } ); # 52
say evaluate( $test{ ref }{ r } ); # 52

Опять же, разработка общего и твердого решения ни в коем случае не является тривиальным проектом. Если вы интересуетесь этими методами с точки зрения Perl, очень хорошая книга - Perl высшего порядка, также доступная онлайн бесплатно.

Что вы можете сделать, это вместо присвоения значения назначить подпрограмму. Например:

my %test;

$test{map}{a} = 32;
$test{map}{b} = sub { return $test{map}{a}+10; };
$test{ref}{r} = sub { return $test{map}{b}(); };

print $test{ref}{r}() . "\n";

$test{map}{a} = 42;

print $test{ref}{r}() . "\n";
Другие вопросы по тегам