Perl 如何修改传递给子例程引用的标量引用?
我有一个将文档转换为不同格式的函数,然后根据文档类型调用另一个函数。除了需要一些清理的HTML文档之外,其他的一切都非常简单,而且根据清理的来源不同,清理是不同的。因此,我的想法是,我可以将对子例程的引用传递给convert函数,这样调用者就有机会修改HTML,就像这样(我不在工作,所以这不是复制和粘贴): 然后被称为:Perl 如何修改传递给子例程引用的标量引用?,perl,pass-by-reference,subroutine,Perl,Pass By Reference,Subroutine,我有一个将文档转换为不同格式的函数,然后根据文档类型调用另一个函数。除了需要一些清理的HTML文档之外,其他的一切都非常简单,而且根据清理的来源不同,清理是不同的。因此,我的想法是,我可以将对子例程的引用传递给convert函数,这样调用者就有机会修改HTML,就像这样(我不在工作,所以这不是复制和粘贴): 然后被称为: Converter->new->convert("./whatever.html", sub { s/<html>/<xml>/i });
Converter->new->convert("./whatever.html", sub { s/<html>/<xml>/i });
Converter->new->convert(“./whater.html”,sub{s///i});
我已经尝试了一些不同的方法,但是我不断地得到“在替换中使用未初始化的值(s//)”。有没有办法做我想做的事
谢谢试试这个:
Converter->new->convert("./whatever.html", sub { ${$_[0]} =~ s/<html>/<xml>/i; });
请记住,
s//
本身在$\uu
上运行,但标量引用作为参数传递到回调子函数中,因此位于@
数组中
因此,您可以将回调子对象更改为以下内容:
sub { my ( $ref ) = @_; $$ref =~ s/<html>/<xml>/i }
然后
sub { $_[0] =~ s/<html>/<xml>/i }
sub{$\u0]=~s///i}
(只要参数是标量变量而不是文字字符串,这实际上会修改原始字符串。)如果是我,我会避免修改标量引用,只返回更改后的值:
sub _convert_html
{
my ($self, $filename, $coderef) = @_;
my $html = $self->slurp($filename);
$html = $coderef->( $html ); #this modifies the html
$self->save_to_file($filename, $html);
}
但是,如果您想修改sub的参数,那么在Perl中所有的子参数都是通过引用传递的(sub调用的参数的别名是@
)。因此,您的转换子项可以如下所示:
sub { $_[0] =~ s/<html>/<xml>/ }
sub _convert_html
{
my ($self, $filename, $coderef) = @_;
my $html = $self->slurp($filename);
$coderef->() for $html;
$self->save_to_file($filename, $html);
}
用于的是正确本地化$的一种简单方法。您还可以执行以下操作:
sub _convert_html
{
my ($self, $filename, $coderef) = @_;
local $_ = $self->slurp($filename);
$coderef->();
$self->save_to_file($filename, $_);
}
在阅读以下任何答案之前:您可能希望尝试在每个子例程级别添加一些print语句,以查看作为参数得到的内容是否与您认为应该得到的内容匹配。提示:替换coderef中的print语句应该会引导您找到答案。感谢您的详细解释:-)这需要大量复制:首先复制到参数堆栈上,然后更改它,然后复制回参数堆栈。如果你必须处理很多很多页面,这可能会造成伤害。请注意,如果速度很重要,local
比for
快,只有一个项目。请注意,如果你注意到local和for之间的速度差,你就犯了其他错误。此外,Sub::AliasedUnderscore是一种比local或for更干净的方法。对于映射代码示例,我想知道我希望返回值是什么。:)@布莱恩:真的;通常我会编写一个转换子函数来返回新值,而不是使用引用。
sub { $_[0] =~ s/<html>/<xml>/ }
sub _convert_html
{
my ($self, $filename, $coderef) = @_;
my $html = $self->slurp($filename);
$coderef->() for $html;
$self->save_to_file($filename, $html);
}
sub _convert_html
{
my ($self, $filename, $coderef) = @_;
local $_ = $self->slurp($filename);
$coderef->();
$self->save_to_file($filename, $_);
}