Почему не работает моя функция Perl? - PullRequest
4 голосов
/ 11 апреля 2009

У меня проблемы с функцией, которую я написал ...

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) = @_; затем копирует их? Как мне это исправить?

Ответы [ 4 ]

10 голосов
/ 11 апреля 2009
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 (..) = @_ копирует аргументы. Поэтому, если вы изменяете переменную, вам нужно вернуть ее, если она не глобальная.

8 голосов
/ 11 апреля 2009

Вы изменяете копию $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") неработоспособными.

4 голосов
/ 11 апреля 2009

Это часть «подпрограммы» подпрограммы, которая делает копии данных.

Если вы измените аргументы @_ напрямую, они будут работать так, как вы ожидаете. Это, однако, не очень читабельно. : -)

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.]
0 голосов
/ 12 апреля 2009

Вот вариант того, как это сделать, который почти идентичен вашему коду с небольшим отличием.

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;

Это поведение явное вместо неявное . На практике это работает идентично час. Owens result, но использует скалярные ссылки вместо того, чтобы полагаться на понимание поведения массивов.

Это сделает более очевидным для любого читающего ваш код, что функция TemplateReplace намеренно изменяет $ text.

Кроме того, он скажет вам, что вы используете его неправильно, крикнув:

Can't use string ("This  is a test.") as a SCALAR ref while "strict refs" in use at replace.pl line 9.

Если вы случайно забыли \ где-нибудь.

...