Perl: Определить хеш со ссылкой на тот же хеш, $this-> {ключ}?

Как был бы я создавать хеш как следование:

my %hash = (key1=>"Something", key2=>$hash{key1} . "Else");

Разве это не может быть сделано в то время как, когда я объявляю хеш? До сих пор единственная вещь, которую я придумал, была:

my %hash = (key1=>"Something");
$hash{key2} = $hash{key1} . "Else";
5
задан SJaguar13 27 January 2010 в 16:53
поделиться

7 ответов

Почему бы не использовать промежуточную переменную?

my $common_value = 'Something';
my %some_hash = ( k1 => $common_value, k2 => $common_value.'Else' );

Обновление

kemp спросило, зачем нам нужна промежуточная переменная. Я могу интерпретировать этот вопрос двумя способами, постараюсь ответить на обе интерпретации.

  1. Почему вы не можете сделать мой %hash = ( k1 => 'foo', k2 => $hash{k1}. 'bar');?

    Правая сторона (rhs) выражения оценивается перед левой стороной (lhs). Таким образом, когда определяется значение для k2, ассигнация к %hash еще не произошла. На самом деле %hash еще даже не создан и не введен в блокнот. (%hash здесь лексическая переменная, поэтому она не попадет в таблицу символов.)

  2. Зачем использовать переменную, а не другой метод?

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

    мой $cv1 = sub_result() * 5;
    мой $cv2 = "Число: $cv1";
    
    my %h = (
     k1 => $cv1, 
     k2 => $cv2,
     k3 => "Numero: $cv1",
     k4 => "Большие $cv2",
     k5 => "Круглый $cv2",
     k6 => "Целый $cv2",
     k7 => "-$cv1",
    );
    

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

    используйте Scalar::Util qw(reftype);
    
    my @init = ( 
     [ клавиша 1 = ] Стоимость ],
     [ key2 => \&make_a_value, 'key1' ],
     [ key3 => \&another_way, 'key2' ],
    );
    
    мой %h; 
    за мой $spec ( @init ) {
     мой $key = сдвиг @$spec;
     my $value = shift @$spec;
     my @args = @$spec;
    
     if( reftype $value eq reftype sub {} ) {
     $значение = $значение->( @h{ @args } );
     }
    
     $h{$key} = $value;
    }
    

    В любом случае, когда этот вопрос организован, выбор метода зависит от многих деталей, которые являются специфическими для данного случая. Таким образом, мы остаемся с необходимостью делать общие утверждения. Промежуточные переменные - это один из хороших способов подхода к проблеме ОП. Должны ли они использоваться в его конкретном случае, я не могу сказать.

11
ответ дан 18 December 2019 в 06:22
поделиться

В точке, где вы определяете хеш, $ Hash {Key1} не существует, поэтому вы не можете сделать это в одном утверждении. Вы можете сделать свое собственное решение и использовать клавишу ключа1 после того, как вы определили его.

4
ответ дан 18 December 2019 в 06:22
поделиться
- 2485542-

Что не так с

my %hash = ( key1 => "Something", key2 => "Something" . "Else" );

?

Да, я знаю, что это заполнители, но все, что они, возможно, вы знаете их в то время, когда вы строете хэш (или вы не построили Это вообще), так почему бы тебе просто присоединиться к ним вместе?

1
ответ дан 18 December 2019 в 06:22
поделиться

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

$_->{key2} = $_->{key1} . "Else" for my $hash = { key1 => "Something" };
0
ответ дан 18 December 2019 в 06:22
поделиться

При создании промежуточной переменной снаружи от% HAHH отключается, затем использование блока DO может сделать его более эстетически приятным:

my %hash = (
    do {
        my $s = 'Something';
        ( key1 => $s, key2 => $s . 'Else' );
    },
);

/ I3AZ /

0
ответ дан 18 December 2019 в 06:22
поделиться

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

  • Вы можете использовать Tie:: Hash, который позволяет сделать объект доступным с синтаксисом хэша и разыменованием стиля хэша (->{key1}), дополнительную информацию об этом методе можно найти с помощью perldoc perltie, а также на man-странице, ссылки на которую приведены выше для Tie: :Hash;
  • Вы можете отказаться от идеи использования хэша; и использовать объект или даже Moose, что позволит инициализировать объект из хэша, разделяя его значение. В реальном примере я не вижу смысла делать это.

Вот пример Moose.

package Class;
use Moose;
has [qw/key1 key2/] => ( isa => 'Str', is => 'rw', init_arg => 'key1' );

my $o = Class->new( { key1 => 'foobar' } );
print $o->key1, $o->key2;
0
ответ дан 18 December 2019 в 06:22
поделиться

Это не может быть сделано по 2 причинам:

  1. в процессах времени Perl Key2 => $ Hash {Key1} , он еще не связал память, выделенную Ключ 1 с хеш-именем хеш. Другими словами, $ hash {Key1} не указывает на правильное место в памяти до Key2 => $ Hash {Key1} уже назначается.

  2. Предыдущая причина не составила дополнительную проблему: вы еще не разместили % HASH в таблицу символов к тому времени, когда вы обрабатываете Key2 => $ Hash {Key1} (Опять же порядок анализа / оценки), поэтому компилятор будет BARF, если вы используете строгий; , как вы всегда должны. Этот легко крестится с объявлением моего% HASH в предыдущем операторе, но № 1 нет.

9
ответ дан 18 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: