【问题标题】:Why won't my Perl function work?为什么我的 Perl 函数不起作用?
【发布时间】:2010-10-18 22:24:27
【问题描述】:

我编写的函数有问题...

sub TemplateReplace
{
    my($regex, $replacement, $text) = @_;
    $text =~ s/($regex)/($replacement)/gs;
}

my $text = "This is a test.";
TemplateReplace("test", "banana", $text);

但它不起作用。我认为参数是在 Perl 中通过引用发送的。 my($regex, $replacement, $text) = @_; 行会复制它们吗?我该如何解决这个问题?

【问题讨论】:

  • 在我们弄清楚如何解决它之前,您必须解释您想要发生的事情。您想更改原始变量,还是获取显示修改的新字符串?这是Chas之间的区别。和阿德南的答案。 :)
  • 如果您想神奇地编辑传递的参数,那么 Chas 的答案就是您要寻找的答案。如果您宁愿以“正确的方式”来做,请遵循 Adnan 的做法。从远处改变变量通常是不受欢迎的,它通常只会增加复杂性而没有什么好处。

标签: perl function pass-by-reference


【解决方案1】:
sub TemplateReplace
{
   my($regex, $replacement, $text) = @_;
   $text =~ s/($regex)/($replacement)/gs;
   return $text;
}

 my $text = "This is a test.";
 $text = TemplateReplace("test", "banana", $text);

那里。应该可以的。

是的,你的 my( ..) = @_ 确实复制了参数。因此,如果您要修改变量,则需要返回它,除非它是全局变量。

【讨论】:

  • +1 表示正确的方法,尽管 Chas.欧文斯的回答让我明白了更多。
【解决方案2】:

您正在修改您传入的$text 的副本;这对原件没有影响。

#!/usr/bin/perl

use strict;
use warnings;

my $text = "This is a test.";

template_replace(qr/test/, "bannana", $text);

print "$text\n";

sub template_replace {
    my $regex       = shift;
    my $replacement = shift;
    $_[0] =~ s/$regex/$replacement/gs;
}

上面的代码之所以有效,是因为@_ 的元素是传入变量的别名。但Adnan 的答案是更常见的做法。修改传递给函数的参数是令人惊讶的行为,并且会使 template_replace(qr/foo/, "bar", "foo is foo") 之类的东西不起作用。

【讨论】:

    【解决方案3】:

    制作数据副本的是子程序的“赋值”部分。

    如果您直接修改 @_ 参数,它们将按您的预期工作。但是,它的可读性不是很高。 :-)

    use strict;
    umask(0);
    $|=1;
    my $debug = 0;
    
    my $text = "This is a test.";
    
    print "Before 1: [$text]\n";
    TemplateReplace("test", "banana", $text);
    print "After 1: [$text]\n";
    
    print "Before 2: [$text]\n";
    TemplateReplace2("test", "banana", $text);
    print "After 2: [$text]\n";
    
    sub TemplateReplace
       {
       my ($regex, $replacement, $text) = @_;    
    
       $text =~ s/($regex)/($replacement)/gs;
       }
    
    sub TemplateReplace2
       {
       $_[2] =~ s/$_[0]/$_[1]/gs;
       }
    

    返回:

    Before 1: [This is a test.]
    After 1: [This is a test.]
    Before 2: [This is a test.]
    After 2: [This is a banana.]
    

    【讨论】:

      【解决方案4】:

      这里有一个关于如何做到这一点的变体,它与您的代码几乎相同,但略有不同。

      use strict;
      use warnings;
      
      
      sub TemplateReplace {
          my($regex, $replacement, $text) = @_;
          $$text =~ s/($regex)/$replacement/gs;
      }
      
      
      
      my $text = "This  is a test."; 
      TemplateReplace("test", "banana", \$text);
      print $text;
      

      这种行为是显式而不是隐式。在实践中,它的工作原理与Chas. Owens 结果相同,但使用标量引用而不是依赖于理解数组的行为。

      这将使阅读您的代码的任何人更清楚地看到函数“TemplateReplace”是有意修改$text。

      此外,它会告诉你使用错误:

      在 replace.pl 第 9 行使用“严格引用”时,不能使用字符串(“这是一个测试。”)作为 SCALAR 引用。

      如果您碰巧在某处忘记了 \。

      【讨论】:

        猜你喜欢
        • 2014-05-24
        • 2021-03-21
        • 2021-12-18
        • 2011-06-23
        • 1970-01-01
        • 2017-08-18
        • 1970-01-01
        • 2022-11-25
        • 2010-11-16
        相关资源
        最近更新 更多