如何在Perl中使用符号引用?

时间:2009-08-19 06:06:12

标签: perl variables

在Perl中,如果变量保存另一个变量的名称,如何使用第一个变量访问另一个变量?

例如,让

$name = "bob";
@bob = ("jerk", "perlfan");

我应该如何使用$ name来了解bob是什么类型的人? 虽然我不太确定,但我模糊的记忆告诉我它可能与typeglob有关。

7 个答案:

答案 0 :(得分:18)

有几点:

  • 您不是在谈论typeglobs,而是在讨论符号引用
  • 不要使用符号引用 - 它们导致难以追踪错误。
  • 几乎在任何情况下,符号引用似乎都是个好主意,使用基于哈希的数据结构是最好的方法。
  • 当您不想更改哈希值时,请考虑使用Hash :: Util来锁定哈希值。
  • 符号引用不适用于词法变量。
  • Typeglobs不适用于词法变量。
  • 使用词汇变量。
  • 请勿使用符号引用。

有关参考文献的更多信息,请参阅perlreftut(符号和其他)。 有关使用数据结构的帮助,请参阅perldsc。 有关typeglobs的更多信息,请参阅perlmod。 有关词汇变量的更多信息,请参阅perlsub

以下是使用锁定哈希根据变量内容控制对数据的访问的示例:

use strict;
use warnings;
use Hash::Util qw( lock_hash unlock_hash );

my %data;
lock_hash( %data );
#Altering %data is a fatal exception.

unlock_hash( %data );

%data = (
    'bob' => [ 'jerk', 'genius' ],
);
lock_hash( %data );


for my $name (qw/ bob  margaret /) {
    my $info = $data{$name}; # Fatal error when accessing data for margaret.
    print "$name is a\n";
    print map "\t$_\n", @$info;
}

除了所有警告之外,使用符号引用的语法应该是你需要使用它(但你不会):

use strict;
use warnings;

my $name = 'bob';

our @bob = qw/jerk genius/;

my $qualities;

{   no strict 'refs';
    print "$name: ", @$name, "\n";
    $qualities = \@$name;
}

print "$name is a @$qualities\n";  

请注意,数组@bob是使用our声明的。符号引用仅适用于符号表中的值。换句话说,词法变量不适用于符号引用。

如果我没有强调这一点, 不要使用符号引用

答案 1 :(得分:13)

这是非常糟糕的做法。如果需要这样做,则意味着您应该重构代码。也许带有命名键的哈希会更好:

my %data = (
    'bob' => [ 'jerk', 'perlfan' ],
);
my $name = 'bob';

print $data{ $name }->[0], "\n";
print $data{ $name }->[1], "\n";

my $stringified = join ' and ', @{ $data{ $name } };
print $stringified, "\n";

答案 2 :(得分:4)

请参阅perldoc -q "variable name"

  

初学者通常认为他们希望变量包含变量的名称。 ...

简答:不要。答案很长:阅读FAQ条目(也可在您的计算机上找到)。更长的答案:阅读MJD的Why it's stupid to "use a variable as a variable name"Part 2Part 3)。

答案 3 :(得分:3)

你真的不应该这样做,请参阅depesz对替代方案的回答,但是......

{
    no strict 'refs';
    print join(q{, }, @$name);
}

是的,您可以使用字符串标量作为变量引用,并按名称查找变量。

您也可以使用typeglobs执行此操作,请参阅符号模块以获得简单的方法。

答案 4 :(得分:2)

通常当您认为需要使用符号引用时,使用哈希(关联数组)可以更好地服务。

use strict;
use warnings;

my %user = (
  'bob' => [qw' jerk perlfan '],
  'mary' => 'had a little lamb',
);

{
  for my $name (qw'bob mary susan'){
    if( exists $user{$name} ){

      if( ref($user{$name}) eq 'ARRAY' ){
        print join( ' ', @{$user{$name}} ), "\n";

      }else{
        print $name, ' ', $user{$name}, "\n";
      }

    }else{
      print "$name not found\n";
    }
  }
}

结果:

jerk perlfan
mary had a little lamb
susan not found

如果您认为真的需要使用符号引用,那么这是一种更安全的方法。

use strict;
use warnings;

# can't use my
our @bob = ("jerk", "perlfan");
our $mary = 'had a little lamb';

{
  for my $name (qw'bob mary susan'){
    if( exists $::{$name} ){
      my $ref = $::{$name};

      if( *{$ref}{ARRAY} ){
        print join(' ',@$ref), "\n";

      }elsif( *{$ref}{SCALAR} ){
        print "# $name is not an array, it's a scalar\n";
        print $name, ' ', $$ref, "\n";
      }

    }else{
      print "$name not found\n"
    }
  }
}

返回:

jerk perlfan
# mary is not an array, it's a scalar
mary had a little lamb
susan not found

你应该注意到安全的符号引用更难,这就是你不应该使用它们的原因。

除非你当然是专家做一些先进的事。

答案 5 :(得分:0)

no strict 'refs';
print "$name is @$name\n";

答案 6 :(得分:0)

符号引用值得避免,但如果您真的想要使用它们,它们的使用语法与常规引用相同:请参阅http://perlmonks.org/?node=References+quick+reference