如何使用Perl更加懒惰?以及其他关于编程习惯的各种问题



昨晚,我写了大约200行糟糕的perl代码,其中包括意大利面条代码、无法调试的未定义变量等等。最后,我把它挂在PerlMonks上等待。我得到了最有用的回应:

在一个sub中,有200多行带有输入解析的意大利面条代码,这与其他所有内容交织在一起。难怪你在调试这个小狗时遇到了麻烦!一些可能有助于清理的提示:

  • 重构代码,将所有输入解析从LHCC子中移出,然后将解析后的数据传递到子中。这使您可以编写和调试子,而不必从一开始就正确地进行输入数据解析
  • 不要使用goto
  • 不要在if/elsif/elses语句中使用空的{}-它们掩盖了失败条件
  • 不要重复代码块-使用sub。它包括大量代码因长而无意义的错误消息而失效的地方。使用sub并传递要包含在消息中的上下文。这将清理代码并帮助调试逻辑错误
  • 不要为不可能发生的事情编写代码(n%2只能是0或1),以避免代码混乱和逻辑模糊
  • 使用"提前退出"循环旁边的循环。这样可以避免嵌套代码,并使其更易于理解
  • 在使用$key之前,请检查它(并死亡)
  • 为什么我的@StatementsKeys=keys%Statements;当@StatementsKeys在任何地方都不使用时

我会在适当的时候跟进您的代码的更新版本,但有很多行需要删除,这需要一段时间!;)。

这对Perl代码来说都是非常好的建议。但我在执行他的建议和真正成为一个懒惰的程序员方面存在问题。出于某种奇怪的原因,我无法在我编程的每一件事中实现他所说的话,我很确定这就是你如何学习真正好的编程。我有两个问题:

首先,如何使这个快速脚本在代码方面得到优化和改进?我认为在我看到这个优化之后,我将能够开始朝着更好的方向使用我的代码。顺便说一句,这不是上面消息中提到的代码。

ORIGINAL:
print "
Welcome to the Casio-Maxim Quadrilateral Identificationn
Algorithm. In order to identify said quadrilateral,n
you must have the coordinates of all 4 vertices.n
When you are ready to input your coordines, typen
'ready.' Type 'quit' to exit the CMQIA.nn";
my $choice = <STDIN>;
if ($choice =~ /quit/i) {
if (!&Unit6()) {
return 0;
}
}
elsif ($choice =~ /ready/i) {
}
else {
print "nCould not interpret, try againn";
goto ORIGINAL;
}
print
"nFor shape ABCD, in which point A has coordinates (X1, Y1), B has coordinatesnn(X2, Y2), C has coordinates (X3, Y3), and D has coordinates (X4, Y4),nnX1 = ";
my $AX = <STDIN>;
chomp $AX;
if ($AX !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nY1 = ";
my $AY = <STDIN>;
chomp $AY;
if ($AY !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nX2 = ";
my $BX = <STDIN>;
chomp $BX;
if ($BX !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nY2 = ";
my $BY = <STDIN>;
chomp $BY;
if ($BY !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nX3 = ";
my $CX = <STDIN>;
chomp $CX;
if ($CX !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nY3 = ";
my $CY = <STDIN>;
chomp $CY;
if ($CY !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nX4 = ";
my $DX = <STDIN>;
chomp $DX;
if ($DX !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
print "nY4 = ";
my $DY = <STDIN>;
chomp $DY;
if ($DY !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
goto ORIGINAL;
}
my $SAB = ($BX - $AX)**2 + ($BY - $AY)**2;
my $AB  = sqrt($SAB);
my $SBC = ($CX - $BX)**2 + ($CY - $BY)**2;
my $BC  = sqrt($SBC);
my $SCD = ($DX - $CX)**2 + ($DY - $CY)**2;
my $CD  = sqrt($SCD);
my $SDA = ($AX - $DX)**2 + ($AY - $DY)**2;
my $DA  = sqrt($SDA);
my $SAC = ($CX - $AX)**2 + ($CY - $AY)**2;
my $AC  = sqrt($SAC);
my $SBD = ($DX - $BX)**2 + ($DY - $BY)**2;
my $BD  = sqrt($SBD);
my $MAB = eval { ($BY - $AY) / { $BX - $AX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $MBC = eval { ($CY - $BY) / { $CX - $BX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $MCD = eval { ($DY - $CY) / { $DX - $CX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $MDA = eval { ($AY - $DY) / { $AX - $DX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $MAC = eval { ($CY - $AY) / { $CX - $AX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $MBD = eval { ($DY - $BY) / { $DX - $BX } };
if ($@) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
goto ORIGINAL;
}
my $ShapeName;
if ($MAB == $MCD) {
if ($MBC == $MDA) {
if ((-1 / $MAB) == $MDA && (-1 / $MBC) == $MCD) {
if ($AB == $BC) {
$ShapeName = "square";
}
else {
$ShapeName = "rectangle";
}
}
else {
if ($AB == $BC) {
$ShapeName = "rhombus";
}
else {
$ShapeName = "parallelogram";
}
}
}
else {
if ($BC == $DA) {
$ShapeName = "isosceles trapezoid";
}
else {
$ShapeName = "trapezoid";
}
}
}
else {
if ($MBC == $MDA) {
if ($AB == $CD) {
$ShapeName = "isosceles trapezoid";
}
else {
$ShapeName = "trapezoid";
}
}
else {
if ((-1 / $MAC) == $MBD) {
$ShapeName = "kite";
}
else {
$ShapeName = "quadrilateral";
}
}
}
print "
Shape ABCD is a $ShapeName.n
AB = $AB or the square root of ($SAB)n
BC = $BC or the square root of ($SBC)n
CD = $CD or the square root of ($SCD)n
DA = $DA or the square root of ($SDA)n
AC = $AC or the square root of ($SAC)n
BD = $BD or the square root of ($SBD)n
Slope of AB = $MABn
Slope of BC = $MBCn
Slope of CD = $MCDn
Slope of DA = $MDAn
Slope of AC = $MACn
Slope of BD = $MBDn";
goto ORIGINAL;

其次,如果我有一位导师来帮助我编码,那会容易得多,这样我就不必一直在PerlMonks和Stack Overflow上发帖,但我可以去问我的导师。不幸的是,从那以后,我失去了与我见过的最好的程序员的联系,他们总是帮助我完成代码,而且我认识的学校里没有一个人真正擅长Perl和Python风格的语言。找到我的代码导师有什么建议吗?

首先,您使用标签和gotos来模拟正常的程序流控制语句。

goto语句在任何语言中都适用的情况非常少。向后跳Perl尤其糟糕。在这种情况下,您可以简单地使用:

while (1) {
...
} else {
print "nCould not interpret, try againn";
continue;
}
...
}

让语言与你一起工作。

接下来,我喜欢你在声明你的变量,你是否也确保你的use strict;在你的文件的顶部,这样声明变量是有用的?

接下来,这部分代码重复了很多次,只做了一些小的更改:

my $AX = <STDIN>;
chomp $AX;
if ($AX !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n"; goto ORIGINAL;
}

你可以把它做成一个像这样的子:

sub parse_input {
my $coord = shift(_@);
chomp $coord;
if ($coord !~ /^-?d+.?d*$/) {
print "nMust be numeric value.n";
return false;
}
return true;
}

然后这样称呼它:

my $AX = <STDIN>;
continue unless (parse_input($AX));
my $AY = <STDIN>;
continue unless (parse_input($AY));
my $BX = <STDIN>;
continue unless (parse_input($BX));
my $BY = <STDIN>;
continue unless (parse_input($BY));
my $CX = <STDIN>;
continue unless (parse_input($CX));
my $CY = <STDIN>;
continue unless (parse_input($CY));
my $DX = <STDIN>;
continue unless (parse_input($DX));
my $DY = <STDIN>;
continue unless (parse_input($DY));

接下来,你有很多重复的代码,看起来像这样:

my $SAB = ($BX-$AX)**2 + ($BY-$AY)**2;
my $AB = sqrt($SAB);

把它分解出来,让语言为你工作。从中找出拼写错误也非常困难,它很密集,很难阅读。

sub pyth {
my ($AX, $AY, $BX, $BY) = @_;
return sqrt(($BX-$AX)**2 + ($BY-$AY)**2);
}

并称之为:

my $AB = pyth($AX, $AY, $BX, $BY);
my $BC = pyth($BX, $BY, $CX, $CY);

等等。

接下来,斜率查找函数使用eval技巧来捕获除以零。然而,我们可以直接检查一下。它要清楚得多。

my $MAB = eval{($BY-$AY)/{$BX-$AX}}; if ($@) {print "nUndefined or No Slope. Sorry, cannot compute.n"; goto ORIGINAL;}

成为:

if ($BX-$AX == 0) {
print "nUndefined or No Slope. Sorry, cannot compute.n";
continue;
}
my $MAB = ($BY-$AY)/($BX-$AX);

当然,因为这是你重复一堆代码的一部分,你应该把它放在一个子中

一个好的经验法则是,如果你必须写两次代码,它可能会保持不变,如果你重复了3次或更多次,或者它很长,你应该把它放在一个函数中。

接下来,您将需要处理未定义坡度的情况,因为这些仍然是有效的形状。

最后,加上一些注释,特别是在形状识别码中,优先级并不是很明显,所以你需要先用通俗的英语解释逻辑。

最新更新