通过这个例子,我想学习编写适应性子程序的最佳方法。
我需要一个修剪文本的子程序(实际上,它是一个借口,我的子程序可以做任何其他事情)。
为了更通用,我希望我的子程序接受不同类型的参数:
my @input = (' A ', ' B', 'C ');
my @trimmed = trim(@input);
trim(\@input);
my $out = trim($input[0]);
返回' A'
trim(\$input[0]);
修剪@input的第一个元素;
trim(\@a, \@b, \@c);
每个字符串数组都被修剪
my $out = trim(\@a, ' A ', ' B');
$ out =(qw / A B /); (要讨论的行为)
这是我目前难看的解决方案:
sub trim {
state $re = qr/^\s+|\s+$/m;
my @a;
for(@_) {
if(ref eq 'SCALAR') { $$_ =~ s/$re//g; }
elsif(ref) { trim(\$_) for(@$_); }
else { push @a, s/$re//gr; }
}
return \@a if @a > 1;
return $a[0] if $a[0];
}
如上所述,是否有更好的解决方案支持不同类型的输入?
这个问题的主要原因涉及我的最终应用程序,其中我携带的文本可以存储在字符串,字符串数组甚至哈希中。
我想写一下会更好:
trim(\@allmytexts);
align(\@allmytexts, align=>'right');
比:
for(@allmytexts) {
trim($_);
align($_, align=>'right');
}
答案 0 :(得分:2)
听起来对我来说太复杂了。使用必须比那更容易阅读和记忆! [1] 。只需trim
取标量(默认为$_
)。
sub trim(_) { $_[0] =~ s/^\s+|\s+\z//rg }
从
开始,所有案例都可以轻松处理$x = trim($x);
@a = map trim, @a;
您也可以制作就地版本。
sub trim_i(_) { s/^\s+|\s+\z//g for $_[0] }
这将使用如下:
trim_i($x);
trim_i for @a;
另一种可能性是获取标量列表(无默认值)。
sub trim {
wantarray
? map s/^\s+|\s+\z//rg, @_
: $_[0] =~ s/^\s+|\s+\z//rg
}
$x = trim($x);
@a = trim(@a);
sub trim_i {
s/^\s+|\s+\z//rg for @_;
}
trim_i($x);
trim_i(@a);
但它有点奇怪。特别是因为my $x = trim($y, $z);
是可能的。
答案 1 :(得分:1)
这个问题不合时宜,很快就会结束。
然而,“在这样的子程序中要求这种行为是否正确?”
我会说不。我很清楚你想要这个子程序在我面前的信息是什么,并且,如果我没有使用它,我肯定会努力记住如何调用它。一两天。你会发现每个人都通过写
来使用它$string = trim($string)
因为这是他们记得的。
看起来你自己也不清楚某些电话是做什么的,因此
my $out = trim(\@a, ' A ', ' B'); $out = (qw/A B/); (behavior to be discussed)
我怀疑你习惯了一种具有不同传递机制的语言,这样的东西会很有用。在Perl中,所有都由别名传递;因此对@_
数组元素的操作等同于对实际参数的相同操作。这意味着如果将该值作为参数传递,子例程可以修改任何可写值。
考虑到这一点,传递引用以指示它将被就地修改,只不过是一个标志,指示子例程的行为方式,以及该例程的阻碍。在使用之前必须取消引用引用。
问问自己,您经常看到常用库函数的行为是这样的。例如,对index
和rindex
进行单独的调用以执行非常类似的操作,并且现有核心运算符lc
与{{1}相似尝试做但它只需要一个参数并返回转换后的结果。 trim
可以被视为sprintf
的变体,只要它知道,如果文件句柄参数是对标量的引用,它应该将字符串放入变量而不是将其写入文件句柄。但它不是那样设计的。
我只能为已定义的问题提供替代解决方案。你没有解释现实生活中的困难,因为你不确定自己printf
应该做什么,我怀疑是否有人可以帮你改进它。
要问自己的其他事情是,当传递引用并且值被修改到位时,返回值应该是多少?很明显它应该在更改后返回值,但是,由于您正在编写自适应代码,如何根据调用是在标量,列表还是无效上下文中更改返回值?或者,更好的是,将trim
设为lvalue subroutine,以便您可以编写类似
trim