Perl: Возврат hashref из подпрограммы

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

my $HASH = {
    "top"=> {
        "instance" => "top_instance",
        "dependencies" => {
            "sub_block1" => {
                "instance" => "sub_block1_instance",
                "dependencies" => {}
            },
            "sub_block2" => {
                "instance" => "sub_block2_instance",
                "dependencies" => {
                    "sub_block3" => {
                        "instance" => "sub_block3_instance",
                        "dependencies" => {}
                    }
                }
            }
        }
    }
};

У меня есть подпрограмма, которая принимает определяемую пользователем строку и возвращает внутреннюю часть хеша из указанного уровня иерархии.

Например, если пользователь указывает «sub_block2», подпрограмма должна вернуть этот хэш:

{
    "sub_block2" => {
        "instance" => "sub_block2_instance",
        "dependencies" => {
            "sub_block3" => {
                "instance" => "sub_block3_instance",
                "dependencies" => {}
            }
        }
    }
}

Это моя подпрограмма:

sub get_starting_point {
    my $string = shift;
    my $config = shift;
    foreach my $key (keys %$config) {
        if($key ne $string) {
            # if current key is not what user asked for, recurse into next level of hierarchy
            if (exists $$config{$key}{dependencies}) {
                &get_starting_point($$config{$key}{dependencies});
            }
        } else {
            # we found the key, return the hash under this hierarchy
            my $tempHash = {$key => $$config{$key}};
            print ref($tempHash); # correctly prints HASH
            print Dumper($tempHash); # correctly prints out the sub-hash
            return $tempHash; # I am expecting this return value to be a hash-ref
        }
    }
}

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

Вот как я называю эту подпрограмму.

my $subHash = get_starting_point("sub_block2",$HASH);
print ref($subHash); # is not a ref
print Dumper($subHash); # prints nothing

Что я делаю неправильно!?!?

РЕДАКТИРОВАТЬ: Обновлен вопрос с моей точной проблемой. Похоже, простой пример, который я использовал раньше, работал, как ожидалось.


person shikhanshu    schedule 21.11.2014    source источник
comment
В коде, который вы показали, нет ничего плохого. Скопировано и вставлено, добавлен импорт, удалены ваши комментарии в стиле c (используйте # для комментариев perl), и он напечатан, как и ожидалось. Можете ли вы показать свой точный код? Используете ли вы строгие и предупреждения?   -  person Nate    schedule 21.11.2014
comment
Я подозреваю, что проблема возникает, когда вы пытаетесь использовать хэш-ссылку; показать, что вы пытаетесь там. perlmonks.org?node=References+quick+reference содержит несколько полезных правил как использовать ссылку   -  person ysth    schedule 21.11.2014


Ответы (2)


Вы возвращаете значение, которое оценивает foreach (в силу того, что оно является последним оператором подпрограммы). Не удивительно, что это не отсылка.

&get_starting_point($$config{$key}{dependencies});

должно быть

my $rv = get_starting_point($config->{$key}{dependencies});
return $rv if $rv;

И добавьте return undef; в конце вместо того, чтобы полагаться на то, что foreach вернет что-то ложное.

sub get_starting_point {
    my $string = shift;
    my $config = shift;
    for my $key (keys %$config) {
        if ($key eq $string) {
            return { $key => $config->{$key} };
        }

        if ($config->{$key}{dependencies}) {
           my $rv = get_starting_point($config->{$key}{dependencies});
           return $rv if $rv;
        }
    }

    return undef;
}

Примечания:

  • Пожалуйста, не добавляйте к дополнительным вызовам префикс &. Ты хоть знаешь, что это делает?
  • Большинство людей считают $config->{$key} более читаемым, чем $$config{$key}.
person ikegami    schedule 21.11.2014
comment
Идеально. Я понял, что возврат был проблемой. Но не подумал вернуться из цикла foreach, который на самом деле является последним оператором, выполняемым в подпрограмме. - person shikhanshu; 21.11.2014
comment
Спасибо за помощь! Что делает & делает для вызовов подпрограмм? Я всегда использовал их. Я прочитал эту ссылку, чтобы получить больше объяснений: stackoverflow.com/questions/1347396/, и я больше не буду ее использовать! - person shikhanshu; 21.11.2014
comment
Вызывает игнорирование прототипа. - person ikegami; 21.11.2014

Ой. Я предполагал, что оператор return в рекурсивной функции немедленно выходит из рекурсии и возвращает значение. Это не так. Поэтому, когда рекурсия идет настолько глубоко, насколько это возможно, и начинает возвращаться обратно, возвращаться уже нечего.

Я решил эту проблему, установив глобальную переменную вне подпрограммы, а внутри подпрограммы я просто устанавливаю эту глобальную переменную в подхеш.

Это служит моей цели!

person shikhanshu    schedule 21.11.2014
comment
ой, плохо. Нет причин для глобального. - person ikegami; 21.11.2014