解引用散列而不创建本地副本 [英] dereferencing hash without creating a local copy

查看:122
本文介绍了解引用散列而不创建本地副本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码行9创建一个散列的本地副本。对%d的任何更改都不会提供对全局%h变量(行:5)的更改。我必须使用引用(行:8)来提供对%h的更改。



有没有任何方法可以在不创建本地副本的情况下对子集中的散列进行解引用?
我在问,因为我有很多引用的复杂记录,并且在引用它的时候,解引用会容易得多。

  1#!/ usr / bin / perl -w 
2使用strict;
3使用警告;
4
5 my%h;
6 sub a {
7
8 my $ href = shift;
9我(%d)=%{$ href}; #这将复制全局%h
10
11 $$ href {1} = 2; #这会改变全局%h
12 $ d {2} = 2; #这不会改变全局%h
13}
14 a(\%h);
15打印标量(键%h)。 \\\
;



----------------



感谢您的回复。



问题是我可以在子节点中为%h创建某种别名/绑定 。
我想改变%d中子节点%h的上下文。
当我创建%d时,他会创建%h的本地副本 - 有什么方法可以避免这种情况,还是必须始终使用引用?


----------------



还有一次: )我知道$ href的工作。我读过教程/手册/文档等
我没有在那里找到答案 - 我认为这是不可能的,因为它没有写在那里,但谁知道。



我想完成这样的行为:

  6 sub a {
7 $ h { 1\" } = 2;
8}

相当于:

  6 sub a {
8 my $ href = shift;
11 $$ href {1} = 2; #这将改变全局%h
11 $ href-> {1} = 2; #这将改变全局%h

现在如何在%d的帮助下做到这一点 - 这实际上可能吗?

  6 sub a {
7 my%d = XXXXXXXXX
.. }

我应该在XXXXXXXXX下指向%h而不创建本地副本?

解决方案

要创建值的本地别名,您需要使用Perl的包变量,可以使用typeglob语法(和 local 来限定别名):

 #!/ usr / bin / perl -w 
使用strict;
使用警告;

my%h;

sub a {
my $ href = shift;

我们的%别名; #创建包变量(for strict)

local * alias = $ href;
#在这里我们告诉perl将hashref安装到typeglob的别名
#perl中会自动将hashref放入
的HASH槽中使%alias引用的glob在散列。
#local用于限制对当前动态范围的更改。
#实际上它是这样做的:* {别名} {HASH} = $ href

$$ href {1} = 2; #这将改变全局%h
$ alias {2} = 2; #这也将改变全局%h
}
a(\%h);
打印标量(键%h)。 \\\
; #打印2

这是一项相当先进的技术,因此请务必阅读 local typeglobs ,所以你明白到底发生了什么(特别是从 local 之后的一个子例程也将包含%alias ,因为 local 表示一个动态范围,本地化将在 a 返回时结束。)



如果您可以安装 Data :: Alias CPAN 中的其他别名模块之一,您可以避免包变量并创建一个词法别名。上述方法是无需额外模块的唯一方法。


I the code bellow line 9 creates a local copy of a hash. Any changes to the %d will not provide changes to global %h variable (line: 5). I have to use reference (line: 8) to provide changes to %h.

Is there any way to dereference hash in a sub without creating a local copy? I am asking since I have complicated record with many references and navigating around it with dereferences would be much easier.

  1 #!/usr/bin/perl -w
  2 use strict;
  3 use warnings;
  4 
  5 my %h;
  6 sub a {
  7 
  8     my $href = shift;
  9     my(%d) = %{$href};   # this will make a copy of global %h
 10     
 11     $$href{1}=2;     # this will make a change in global %h
 12     $d{2}=2;         # this will not a change in global %h
 13 }   
 14 a(\%h);
 15 print scalar (keys %h) . "\n";

----------------

Thanks for the replies.

The question is can I make some kind of "alias/bind" to %h in a sub. I would like to change the context of %h in a sub with %d. Whenever I create %d he makes local copy of %h - is there any way to avoid that or do I have to use references all the time?

----------------

One more time :) I know how $href's work. I read tutorial / manuals / docs etc. I didn't find the answer there - I assume that this is not possible since it wasn't written there, but who knows.

I want to accomplish such behavior:

  6 sub a {
  7     $h{"1"}=2;
  8 }

Which is equivalent to that:

  6 sub a {
  8      my $href = shift;
  11     $$href{1}=2;     # this will make a change in global %h
  11     $href->{1}=2;    # this will make a change in global %h

Now how to do that with the help of %d - is it actually possible?

6 sub a {
7        my %d = XXXXXXXXX
.. }

What should I put under XXXXXXXXX to point to %h without creating a local copy?

解决方案

To create a local alias of the value, you need to use Perl's package variables, which can be aliased using the typeglob syntax (and local to scope the alias):

#!/usr/bin/perl -w
use strict;
use warnings;

my %h;

sub a {
    my $href = shift;

    our %alias; # create the package variable (for strict)

    local *alias = $href;
        # here we tell perl to install the hashref into the typeglob 'alias'
        # perl will automatically put the hashref into the HASH slot of
        # the glob which makes %alias refer to the passed in hash.
        # local is used to limit the change to the current dynamic scope.
        # effectively it is doing:  *{alias}{HASH} = $href

    $$href{1}=2;     # this will make a change in global %h
    $alias{2}=2;     # this will also make a change in global %h
}
a(\%h);
print scalar (keys %h) . "\n";  # prints 2

This is a fairly advanced technique, so be sure to read the Perl docs on local and typeglobs so you understand exactly what is going on (in particular, any subs called from within the a subroutine after the local will also have %alias in scope, since local denotes a dynamic scope. The localization will end when a returns.)

If you can install Data::Alias or one of the other aliasing modules from CPAN you can avoid the package variable and create a lexical alias. The above method is the only way to do it without additional modules.

这篇关于解引用散列而不创建本地副本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆