0

I have the following code, I wrote to truncate large values.

   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;
        }

and I am calling this subroutine using the call in another subroutine say

  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});
        }

But when I check $EMAIL{$tag} is still pointing to non-truncated value. am I doing something wrong?

4

3 回答 3

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);
于 2013-09-07T17:46:40.243 回答
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],您将更改原始参数。

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

于 2013-09-07T17:51:14.477 回答
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})
于 2013-09-07T17:47:46.467 回答