为什么以下递归因子在Perl中失败,即使它在C ++和Java中有效?
爪哇:
public static long factorial(int n) {
if (n == 0) {
return 1;
} else {
return factorial(n-1) * n;
}
}
C ++:
long factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
但是这个在Perl(use Carp;
)中失败了:
sub factorial {
my $n = shift || croak "null value for argument";
return 1 if $n == 0; # base case
return $n * factorial($n-1);
}
错误消息(第10行是main()
中调用函数的地方,第16行是第二个return
语句):
null value for argument at ./fact1.pl line 14.
main::factorial(0) called at ./fact1.pl line 16
main::factorial(1) called at ./fact1.pl line 10
(以下编辑归功于Matt Jacob在原版中指出我的遗漏。)
原始版本,没有鲤鱼,但有|| return
,错误消息是:
Use of uninitialized value in multiplication (*) at ./fact1.pl line 16.
这是在没有命令行参数时尝试使脚本保持静默的结果。 (没有关于uninitialized value
的投诉。)
对基本案例的一个小修改使它在Perl中也可以工作:
sub factorial {
my $n = shift || croak "null value for argument";
return 1 if $n == 1; # base case
return $n * factorial($n-1);
}
(当然,代价是取消处理0
(零)输入。)
经验教训
shift;
0
(零)表示false
答案 0 :(得分:6)
特别是,在布尔表达式中使用时,数字0被认为是假的。所以当你这样说时
my $n = shift || croak "null value for argument";
如果shift
将0作为参数,则会将其视为false,这意味着||
运算符需要计算其第二个操作数。
幸运的是,Perl的编写者预见到了这种用例,因此他们定义了一个替代或运算符。 ||
检查第一个值是否真实,//
检查是否定义了第一个值。
my $n = shift // croak "null value for argument";
这将按照您的意图执行,除非$n
可能是文字值undef
。在这种情况下,你需要一些更复杂的内省来检查参数是否存在,但是为了这个阶乘函数的目的,这应该足够了。