Smartelf
Smartelf

Reputation: 879

How to store a reference in perl that is itself not a reference

I have a recursive function that uses ref to walk down a data structure recursively. If ref returns an empty string, then a callback is called. My problem is that I need to store a hash-ref in my data structure that will be treated as a scalar by my function.

In essence, what I need is to do something like this;

    my %hash = fillHash();
    $hash{'abc'}{'def'} = \%hash;

I was wondering if there was some way of storing \%hash in such a way that it would be treated as a scalar and not a reference. possibly like/

     $hash{'abc'}{'def'} = scalar \%hash;

I am simply looking a way to add a link to the parent node of my data structure, yet still being able to recursively walk it.

Thanks

Upvotes: 1

Views: 211

Answers (3)

Alan Curry
Alan Curry

Reputation: 14721

First of all, you should realize that all references are scalars by definition.

What you want is something that works as a reference everywhere but inside your walking function. That's not really achievable by any kind of magic reference. The walking function is where the logic is going to have to be added. You can make it keep track of things it has already seen:

my %h = (
    foo => "bar",
    inner => {
        foo => 42
    }
);

$h{inner}{parent} = \%h;

sub walk
{
    my ($h, $cb, $path, $seen) = @_;
    $path //= "";
    $seen //= {};
    $seen->{$h}=1;
    while(my ($k, $v) = each %$h) {
        if(ref($v)) {
            walk($v, $cb, "$path/$k", $seen) if !$seen->{$v};
        } else {
            $cb->($k, $v, "$path/$k");
        }
    }
}

walk(\%h, sub {
  my ($key, $value, $path) = @_;
  print "walker found $key ($path) => $value\n";
});

Or you could just make it recognize certain keys like parent as special and skip them.

Upvotes: 1

Axeman
Axeman

Reputation: 29854

You could use what I did to differentiate values from structure, I call them "indirect arrays" (in my case).

In your case it would look like this:

 $hash{'abc'}{'def'} = scalar \\%hash;

ref( $hash{'abc'}{'def'} ) is 'REF', in case you're wondering. And you can then decide that you need to dereference it twice:

$hash_ref = ${ $hash{'abc'}{'def'} };

Upvotes: 3

zostay
zostay

Reputation: 3995

I think @MarkCanlas has the right solution in his suggestion to consider a different way to structure your data. Barring that, you could take a double reference.

my $scalar_ref = \%hash;
$other_hash{abc}{def} = \$scalar_ref;

Now, when you check the ref of that you'll get back "REF" and can do something different.

Upvotes: 2

Related Questions