【发布时间】:2017-02-23 21:00:14
【问题描述】:
为什么以下递归阶乘在 Perl 中会失败,即使它适用于 C++ 和 Java?
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(零)输入为代价。)
经验教训
- 问题出在我认为的不同位置
- Perl 代码的错误在于它试图比 C++ 或 Java 代码 sn-ps 做更多的事情(一种非常粗略的方法)
- 不同的错误信息应该给了我提示
- 以下内容可以帮助我定位问题:
- 删除
shift;之后的所有内容 - 记住
0(零)表示false
- 删除
- Logical Defined-Or 从 Perl 5.10 开始就存在
- 至于正确的错误处理,this page 提供了很好的概述。
【问题讨论】:
-
回复“why not the same if/else”:java来自一个课程示例。 (所以大括号)。 C++,我在 Perl 之后的测试失败了。 (但我喜欢在简单的表达式中去掉大括号)。在 Perl 中,等效的“无括号”解决方案是条件子句最后出现。
-
您在使用
croak之前关于错误消息的陈述与您问题中的代码不匹配。如果您调用factorial(),$n将是undef,并且警告将是关于“未初始化的 $n 在数字 eq”。 (但是undef会隐式转换为 0,并且该函数仍将返回 1。)真正的问题是:为什么您要使用未定义/空值调用该函数并期望它在 Perl 中不能工作用其他语言工作! -
@MattJacob 你是绝对正确的。它不仅仅是“没有”,而是带有“|| return”。当没有命令行参数时,它是为了帮助我。 (我将编辑问题并添加您的评论。)
标签: perl function recursion error-handling parameter-passing