如何通过perl中的引用传递哈希值

时间:2013-09-07 17:38:16

标签: perl variables hash reference subroutine

我有以下代码,我写了截断大值。

   sub truncate_large_email_tag
    {
      my($email_tag) = @_;
      my $size = length($email_tag);

    if ($size>5000) { 
        my $fragment = substr($email_tag,0,5000);
        $email_tag = $fragment;
        #log_it( "\n\Truncated Large Email tags\n\n") if $TRACE;
        }

我正在调用这个子程序,使用另一个子程序中的调用说

  sub do_something
   {
  #some code here # CFG_PASS is a hash

        $EMAIL{$tag}=$CFG_PASS{$typ}{$tag}{$where . '_DEFAULTS'}; #Email        
        #tag initialized here
        truncate_large_email_tag($EMAIL{$tag});
        }

但是当我检查$ EMAIL {$ tag}时仍然指向非截断值。我做错了什么?

3 个答案:

答案 0 :(得分:6)

Perl总是通过引用传递。问题是你没有修改参数,而是修改了你在函数中创建并在其中复制参数的变量(my ($email_tag) = @_;)。

更改

my $fragment = substr($email_tag, 0, 5000);
$email_tag = $fragment;

my $fragment = substr($email_tag, 0, 5000);
$_[0] = $fragment;

$_[0] = substr($email_tag, 0, 5000);

$_[0] = substr($_[0], 0, 5000);

substr($_[0], 5000) = '';

所以你最终得到了

sub truncate_inplace {
    substr($_[0], $_[1]) = ''
        if length($_[0]) > $_[1];
}

truncate_inplace($EMAIL{$tag}, 5000);

但为什么不使用

sub truncate {
    my ($s, $max_len) = @_
    return length($s) > $max_len ? substr($s, 0, $max_len) : $s;
}

$EMAIL{$tag} = truncate($EMAIL{$tag}, 5000);

答案 1 :(得分:2)

正如您所推测的那样,您正在按值传递$EMAIL{$tag},因此您的修改会在子结束后丢失并且原始文件保持不变。有两种方法可以做你想做的事。

方式一:

truncate_large_email_tag(\$EMAIL{$tag});

这将对$EMAIL{$tag}的引用传递给子例程。在sub中,你需要取消引用它来完成你的工作:

my ( $email_tag_ref ) = @_;
my $email_tag = $$email_tag_ref;

可以缩写为:

my $email_tag = ${ $_[0] };

方式二:

利用@_特殊且别名调用参数这一事实。

$_[0] = substr($email_tag,0,5000);

通过直接分配到$_[0],您将更改原始参数。

就个人而言,我更喜欢方式,因为它更明确。

答案 2 :(得分:1)

在perl中,标量参数会自动通过引用传递,这就是你在这里所拥有的。你不是想传递整个哈希;你只是想修改其中的一个值。

您可以通过分配回@_来修改子程序调用的参数,如下所示:

sub truncate_large_email_tag
{
    my($email_tag) = @_;
    my $size = length($email_tag);

    if ($size>5000) { 
        my $fragment = substr($email_tag,0,5000);
        $email_tag = $fragment;
        #log_it( "\n\Truncated Large Email tags\n\n") if $TRACE;
    }

    $_[0] = $email_tag;  # modify argument in the caller
}

那就是说, 通常更清楚地发送一个明确的引用。为此,在调用时在参数前面加一个反斜杠,并在被调用者中使用额外的$取消引用:

sub truncate_large_email_tag
{
    my ($email_tag_ref) = @_;
    my $size = length($email_tag);

    if ($size>5000) { 
        my $fragment = substr($email_tag,0,5000);
        $$email_tag_ref = $fragment;
        #log_it( "\n\Truncated Large Email tags\n\n") if $TRACE;
    }
}

然后当你打电话时:

truncate_large_email_tag(\$EMAIL{$tag})