Может ли имя хеша Perl (на момент объявления) использоваться внутри того же хеша? - PullRequest
2 голосов
/ 13 апреля 2019

Я объявляю хэш, и во время его объявления я использую его внутри для одного из его элементов в качестве входных данных для другого элемента. Вы можете легко понять следующий код, который не компилируется, так как Strict pragma ON:

my %cob = (
        'a' => 0,
        'b' => 0,
        'z' => sub {
                    my ($a, $b) = ($cob{'a'}, $cob{'b'});
                    return ($a+$b+1);
                }                                       
    );

И это вызывает ошибку времени компиляции.

Итак, мой вопрос заключается в том, как я могу повторно использовать те же элементы хеширования, что и входные данные для других элементов того же хэша во время объявления? Здесь элемент 'a' и 'b' являются входными данными для функции элемента 'z'.

Логически, если хеш не был объявлен, то его нельзя использовать, так как же использовать один элемент в качестве входных данных для другого элемента того же хеша во время объявления? Надеюсь, мне ясно ...

Ответы [ 2 ]

4 голосов
/ 14 апреля 2019

Рассмотрите возможность создания общих $aa и $bb переменных внутри лексического замыкания для создания новых хэшей cob.

sub make_cob {
  my($aa,$bb) = (0, 0);
  { a => \$aa,
    b => \$bb,
    z => sub { $aa + $bb + 1 },
  };
}

Имена переменных $aa и $bb избегайтепредупреждение в документации perlvar для $a и $b на случай, если вам когда-либо понадобится выполнить какую-либо сортировку в make_cob:

  • $a
  • $b
    Специальные переменные пакета при использовании sort .Из-за этой особенности $a и $b не нужно объявлять (используя use vars или our) даже при использовании strict 'vars' Прагма .Не лексизируйте их с помощью my $a или my $b, если вы хотите использовать их в sort блоке сравнения или функции.

Использование одногов виде простого хэша %cob выглядит как

my %cob = %{ make_cob() };
${$cob{a}} = 10;
${$cob{b}} = 20;
print "z: ", $cob{z}(), "\n";

В качестве ссылки на хэш $cob код:

my $cob = make_cob;
${$cob->{a}} = 30;
${$cob->{b}} = 40;
print "z: ", $cob->{z}(), "\n";

Вы можете обернуть их все в анонимные подпрограммы, как в

sub make_cob {
  my($aa,$bb) = (0, 0);
  { a => sub { if (@_) { $aa = shift } else { $aa } },
    b => sub { if (@_) { $bb = shift } else { $bb } },
    z => sub { $aa + $bb + 1 },
  };
}

my $cob = make_cob;
$cob->{a}(40);
$cob->{b}(50);
print "a: ", $cob->{a}(), "\n",
      "b: ", $cob->{b}(), "\n",
      "z: ", $cob->{z}(), "\n";

Но если вы идете ко всем этим неприятностям, сделайте ваши экземпляры початков класса Cob.

package Cob;

use strict;
use warnings;

sub new {
  my($class,$aa,$bb) = @_;
  $_ = defined $_ ? $_ : 0 for $aa, $bb;
  bless { a => $aa, b => $bb } => $class;
}

sub a { $_[0]->{a} }
sub b { $_[0]->{b} }
sub z { $_[0]->a + $_[0]->b + 1 }

1;

Упражнение этого класса с

#! /usr/bin/env perl

use strict;
use warnings;

use Cob;

my $cob = Cob->new(1,2);
print "a: ", $cob->a, "\n",
      "b: ", $cob->b, "\n",
      "z: ", $cob->z, "\n";

Output:

a: 1
b: 2
z: 4
2 голосов
/ 13 апреля 2019
my ($a, $b) = ($cob{'a'}, $cob{'b'});

Чтобы Perl мог скомпилировать этот оператор, %cob должен быть объявлен где-то до оператора, но %cob еще не был объявлен (какэто часть заявления).Решение состоит в том, чтобы объявить %cob перед оператором:

my %cob;   # declare the variable first
%cob = (
        'a' => 0,
        'b' => 0,
        'z' => sub {
                    my ($a, $b) = ($cob{'a'}, $cob{'b'});  # now %cob is known to be a hash
                    return ($a+$b+1);
                }                                       
    );
...