这个问题足以填写一本书。事实上,这正是发生的事情!
Mark Jason Dominus的优秀著作《高阶Perl》可以在线免费获取。
以下是书中引人入胜的前言摘录:
大约在1993年左右,我开始阅读关于Lisp的书籍,并发现了一些重要的东西:Perl更像Lisp,而不是C语言。如果你拿起一本好的 Lisp 书,里面会有一个描述Lisp好特点的章节。例如,Peter Norvig所著的 "人工智能编程范例" 这本书包含一个名为“Lisp的特殊之处”的部分,描述了Lisp的七个特性。Perl共享其中六个特性,而C语言没有共享任何一个特性。这些都是重要的特性,比如一级函数、动态访问符号表和自动存储管理。
不要将以下C编程习惯带到Perl 5中:
if (!(complex logical statement)) {}
,这就是 unless
的用途。goto
打破深度嵌套的循环,next
、last
和 redo
都可以接受循环标签作为参数。perldoc perlsub
和 perldoc perlref
。在Perl 5中应该做的事情:
strict
和 warnings
pragma。perldoc perl
和 perldoc -f function_name
)。structs
一样使用哈希。return unless ($foo)
。但我通常不会在复杂的逻辑语句中使用它。 - szbalintunless
--它与if not
相同(除了操作顺序问题 - 如果有疑问,请使用括号)只是更长 :) - Ether||
或&&
来进行流程控制。但作为一名Perl程序员,使用or
来执行die
操作是非常合理的。那些将and
和or
用于其他目的的人使得代码难以阅读,但or die
则非常清晰易懂。 - Chas. Owens使用最具可维护性、开发时间、可测试性和灵活性等最佳组合解决您的问题。在特定应用上下文之外讨论任何技术、风格或库都没有太大用处。
你的目标不应该是为你的解决方案找问题。学习比你立即计划使用的Perl多一点(并持续学习)。有一天你会遇到一个问题,然后想起“我记得有些东西可能对此有帮助”。
你可能想看一些这些书:
我建议您在编码中逐渐引入新概念。Perl的设计使您无需了解很多即可开始,但您可以在学习更多知识的同时改进您的代码。试图一次掌握许多新功能通常会以其他方式给您带来麻烦。
我认为最大的障碍不是动态方面,而是“电池包含”方面。
我认为perl最强大的方面是:
我注意到C转换器的一件事是过度使用for循环。可以使用grep和map来消除许多循环。
Perl的另一个座右铭是“有多种方法可以做到这一点”。为了攀登学习曲线,您必须经常告诉自己:“肯定有更好的方法来做这个,我不可能是第一个想要做...的人。”然后,您通常可以转向谷歌和CPAN及其荒谬的库数量。
Perl的学习曲线不陡峭,但非常漫长...花时间享受旅程。
foreach
的风格书写。在这里我想指出,在Perl中,“for”和“foreach”是完全相同的东西。 - szbalinteval
字符串形式有一些相当严重的副作用;但在某些情况下,它可能是一种极其优雅的解决方案,比任何替代DP或SP方法都要好得多。eval
字符串形式实现的;或者Try::Tiny异常机制,它使用块形式的eval
。Moose
实现的方面编程(我现在找不到相关的StackOverflow链接 - 如果有人有,请编辑链接)。它在底层使用了DP的符号表访问特性。for($i=1; $i<=50; $i+=2) {
printf("%d ", $i);
}
print "\n";
print join(' ',(grep { $_ % 2 } (1..50))), "\n"; #original
print join(' ',(grep { !($_ % 2) } (1..50))), "\n"; #even
print join(' ',(grep { suba($_) } (1..50))), "\n"; #other pattern
print "@{[grep{$_%2}(1..50)]}\n"; #original
print "@{[grep{$_%2+1}(1..50)]}\n"; #even - WRONG!!!
print "@{[grep{~$_%2}(1..50)]}\n"; #second try for even
print "$_ " for (sort {$a<=>$b} keys %{{1..50}}), "\n"; #orig
print "$_ " for (sort {$a<=>$b} keys %{{2..50}}), "\n"; #even
print "$_ " for (sort {$a<=>$b} values %{{1..50}}), "\n"; #even alt
for (1..50) {
print "$_ " if ($_%2);
} #odd
print "\n";
for (1..50) {
print "$_ " unless ($_%2);
} #even
print "\n";
print map { "$_ " } grep { $_ & 1 } 1..50; #original
print "\n";
print map { "$_ " } grep { !($_ & 1) } 1..50; #even
print "\n";
print map { "$_ " } grep { suba($_) } 1..50; #other
print "\n";
for (1..50) {
if ($_ & 1) {
$odd[++$#odd]="$_ ";
next;
} else {
push @even, "$_ ";
}
}
print @odd, "\n";
print @even;
eval
或其他在纯编译语言(如C)中无法实现的内容。最后一个示例是“动态”的,其中正则表达式中包含了eval
,但确实是非常糟糕的风格:$t='D ' x 25;
$i=-1;
$t=~s/D/$i+=2/eg;
print "$t\n"; # don't let the door hit you on the way out...
for
循环的C 3参数形式可能非常适合。此外,请记住您使用Perl的原因:大概是为了高效的程序员生产力。如果我有一个完全调试好的C代码片段,它恰好可以满足我的需求,并且我需要将其转换成Perl,那么我就会按照C风格在Perl中重写这个愚蠢的东西!这是这种语言的优点之一(但对于更大或团队项目来说也是其弱点,因为个人编码风格可能会有所不同,从而使整体代码难以跟踪。)至少在我的看法中,“动态”的特性并不是非常重要的。我认为你需要考虑的最大区别是,在C或C++中,你通常习惯于只使用库代码带来的相当小的优势。库中已经编写和调试好了,所以很方便,但如果必要的话,你通常可以自己完成相同的事情。对于效率而言,主要是看你能否编写出更专业的东西,是否超过了库作者花费更多时间打磨每个例程的能力。然而,差异很小,除非库例程确实符合你的需求,否则你最好自己编写。
但在Perl中,这种说法不再适用。与C相比,(庞大的)库中的许多内容实际上是用C编写的。除非你编写一个C模块,否则尝试自己编写任何类似的东西几乎肯定会慢得多。因此,如果你能找到一个库例程,它甚至接近你想要的功能,那么你最好使用它。在Perl中,使用预先编写的库代码比在C或C++中更加重要。
良好的编程实践并不特定于个别语言,它们适用于所有语言。从长远来看,您可能会发现最好不要依赖动态语言中可能存在的技巧(例如,可以返回整数或文本值的函数),因为这会使代码更难以维护和快速理解。因此,最终回答您的问题,我认为您不应该寻找特定于动态类型语言的功能,除非您有一些强烈的原因需要它们。保持简单和易于维护-这将在长期内更具价值。
动态语言有很多你只能用它来做的事情,但最酷的是eval
。请参阅此处以获取更多详细信息。
使用eval,您可以执行字符串,就像它是预先编写的命令一样。您还可以在运行时按名称访问变量。
例如,
$Double = "print (\$Ord1 * 2);";
$Opd1 = 8;
eval $Double; # Prints 8*2 =>16.
$Opd1 = 7;
eval $Double; # Prints 7*2 =>14.
变量$Double
是一个字符串,但我们可以将其执行为一个常规语句。这在C/C++中是不可能的。
很酷的一点是,字符串可以在运行时进行操作;因此,我们可以在运行时创建命令。
# string concatenation of operand and operator is done before eval (calculate) and then print.
$Cmd = "print (eval (\"(\$Ord1 \".\$Opr.\" \$Ord2)\"));";
$Opr = "*";
$Ord1 = "5";
$Ord1 = "2";
eval $Cmd; # Prints 5*2 => 10.
$Ord1 = 3;
eval $Cmd; # Prints 5*3 => 15.
$Opr = "+";
eval $Cmd; # Prints 5+3 => 8.
eval
非常强大,就像蜘蛛侠一样,力量伴随责任。明智地使用它。
希望这对你有帮助。
eval
有其使用场景,但在我看来,这些示例都不符合该命令的良好使用。此外,需要注意字符串eval
和块级eval
之间的重要区别。无论如何,我不会鼓励刚学这门语言的程序员专注于eval
。相反,应将其视为最后的选择,特别是字符串eval
,因为通常有更好的方法。 - FMceval
的危险性的看法。事实上,在我的帖子中,我提到它应该小心使用。但这并不改变eval
是动态语言(包括Perl)最独特的功能之一的事实,尽管它有所有的危险性。 - NawaMan