Perl是一种动态、动态类型、高级脚本(解释)语言,与PHP和Python最具可比性。Perl的语法在很大程度上要归功于古老的shell脚本工具,它以过度使用令人困惑的符号而闻名,其中大多数符号是谷歌无法找到的。Perl的shell脚本传统使其非常适合编写胶水代码:链接其他脚本和程序的脚本。Perl非常适合处理文本数据和生成更多的文本数据。Perl广泛、流行、高度可移植且支持良好。Perl的设计理念是“There’s More One Way To Do It”(TMTOWTDI)(与Python相反,Python's“should be One,preference only One the objective Way To Do It”)。
Perl很可怕,但它也有一些很好的弥补功能。在这方面,它就像所有其他创建的编程语言一样。
本文件旨在提供信息,而非福音。它针对的是像我这样的人:
- 不喜欢上的官方Perl文档http://perl.org/因为技术性很强,给了非常不寻常的边缘案例太多的空间
- 通过“公理与范例”最快速地学习新的编程语言
- 希望拉里·沃尔能说到点子上
- 已经知道如何进行一般编程
- 除了完成工作所需的内容之外,不关心Perl。
本文件旨在尽可能简短,但不得更短。
初步说明
你好,世界
一个Perl脚本是一个扩展名为.pl文件
.
这是的全文helloworld.pl(你好世界.pl)
:
使用严格;使用警告;打印“你好,世界”;
Perl脚本由Perl解释器解释,珍珠
或perl.exe文件
:
perl helloworld.pl[arg0[arg1[arg2…]]]
一些即时的注意事项。Perl的语法是高度宽松的,它允许您做一些事情,这些事情会导致具有不可预测行为的看起来模棱两可的语句。我没必要解释这些行为是什么,因为你想避免它们。避免它们的方法是使用严格;使用警告;
在您创建的每个Perl脚本或模块的最顶层。表格声明使用foo;
是杂注。杂注是指向perl.exe文件
,在程序开始运行之前执行初始语法验证时生效。当解释器在运行时遇到这些行时,它们不起作用。
分号,;
,是语句终止符。符号#
开始注释。注释持续到行末。Perl没有块注释语法。
变量
Perl变量有三种类型:标量,阵列和哈希每种类型都有自己的符号:$
,@
和%
分别是。变量声明使用我的
,并保留在范围中,直到封闭块或文件结束。
标量变量
标量变量可以包含:
未定义
(对应于无
在Python中,无效的
PHP格式)
- 数字(Perl不区分整数和浮点)
- 一根绳子
- 对任何其他变量的引用。
my$undef=undef;打印$undef;#打印空字符串“”并引发警告#隐式undef:我的$undef2;打印$undef2;#打印“”并发出完全相同的警告
我的$num=4040.5;打印$num;#"4040.5"
my$string=“world”;打印$string;#“世界”
(参考文献很快就会出现。)
使用.
运算符(与PHP相同):
打印“Hello”(你好)$字符串;#“你好,世界”
“布尔型”
Perl没有布尔数据类型。中的标量如果
语句的计算结果为布尔值“false”,当且仅当它是以下值之一时:
Perl文档反复地声称函数在某些情况下返回“true”或“false”值。实际上,当一个函数被声明返回“true”时,它通常会返回1
,当声称返回false时,它通常返回空字符串,“”
.
弱输入
无法确定标量是包含“数字”还是“字符串”。更准确地说,不应该这样做。标量的行为像数字还是字符串取决于使用它的运算符。当用作字符串时,标量的行为与字符串类似。当用作数字时,标数的行为与数字类似(如果不可能,则发出警告):
我的$str1=“4G”;my$str2=“4H”;打印$str1$字符串2;#“4G4H”打印$str1+$str2;#带有两个警告的“8”打印$str1 eq$str2;#“”(空字符串,即false)打印$str1==$str2;#带两个警告的“1”#经典错误打印“yes”==“no”;#“1”有两个警告;当用作数字时,这两个值的计算结果都为0
教训是在正确的情况下始终使用正确的运算符。有单独的运算符用于将标量作为数字进行比较,并将标量用作字符串进行比较:
#数值运算符:<,>,<=,>=,==,!=,<=>,+*#字符串运算符:lt、gt、le、ge、eq、ne、cmp,.,x个
数组变量
数组变量是由从0开始的整数索引的标量列表。在Python中,这被称为列表在PHP中,这称为阵列。使用带括号的标量列表声明数组:
我的@array=(“打印”,“这些”,“字符串”,“退出”,“for”,“me”,#尾随逗号可以);
您必须使用美元符号来访问数组中的值,因为该值恢复不是数组,而是标量:
打印$array[0];#“打印”打印$array[1];#“这些”打印$array[2];#“字符串”打印$array[3];#“退出”打印$array[4];#“用于”打印$array[5];#“我”打印$array[6];#返回undef,打印“”并引发警告
您可以使用负索引来检索从末尾开始并向后工作的条目:
打印$array[-1];#“我”打印$array[-2];#“用于”打印$array[-3];#“退出”打印$array[-4];#“字符串”打印$array[-5];#“这些”打印$array[-6];#“打印”打印$array[-7];#返回undef,打印“”并引发警告
标量之间没有冲突$变量
和一个阵列@无功功率,无功功率
包含标量条目$var[0]
。然而,读者可能会感到困惑,所以要避免这种情况。
要获取数组的长度:
打印“此数组有”。(标量@数组)。“元素”;#“此数组有6个元素”打印“最后填充的索引是”$#数组;#“最后填充的索引为5”
调用原始Perl脚本时使用的参数存储在内置数组变量 @ARGV公司
.
变量可以插入到字符串中:
打印“Hello$string”;#“你好,世界”打印“@array”;#“为我打印这些字符串”
小心。有一天你会把某人的电子邮件地址放在一个字符串中,"jeff@gmail.com"
。这将导致Perl查找一个名为@gmail公司
插入到字符串中,而没有找到它,从而导致运行时错误。插值可以通过两种方式来防止:通过反斜杠跳过符号,或者使用单引号代替双引号。
打印“Hello\$string”;#“你好$string”打印“Hello$string”;#“你好$string”打印“\@array”;#“@array”打印“@array”;#“@array”
哈希变量
散列变量是由字符串索引的标量列表。在Python中,这被称为词典在PHP中,它被称为阵列.
我的%科学家=(“牛顿”=>“艾萨克”,“爱因斯坦”=>“阿尔伯特”,“达尔文”=>“查尔斯”,);
请注意,此声明与数组声明非常相似。事实上,双箭头符号=>
被称为“胖逗号”,因为它只是逗号分隔符的同义词。哈希是使用包含偶数个元素的列表声明的,其中偶数个的元素(0、2、…)都被视为字符串。
同样,您必须使用美元符号从散列中访问值,因为该值恢复不是散列,而是标量:
打印$scientists{“Newton”};#“艾萨克”打印$科学家{“爱因斯坦”};#“阿尔伯特”打印$科学家{“达尔文”};#“查尔斯”打印$scientists{“Dyson”};#返回undef,打印“”并引发警告
请注意此处使用的大括号。同样,标量之间没有冲突$变量
和散列%无功功率,无功功率
包含标量条目$var{“foo”}
.
您可以将哈希直接转换为具有两倍多条目的数组,在键和值之间交替(反过来也很容易):
我的@scientists=%科学家;
然而,与数组不同,散列的键具有无基础订单。它们将以更有效的顺序返回。因此,请注意重新安排的秩序但保存完好对在结果数组中:
打印“@scientists”;#比如“爱因斯坦-阿尔伯特-达尔文-查尔斯·牛顿-艾萨克”
重述一下,您必须使用方括号从数组中检索值,但必须使用支架从散列中检索值。方括号实际上是一个数值运算符,大括号实际上是字符串运算符。事实上指数提供的是一个数字或字符串,它完全没有意义:
my$data=“orange”;my@data=(“purple”);我的%数据=(“0”=>“蓝色”);打印$data;#“橙色”打印$data[0];#“紫色”打印$data[“0”];#“紫色”打印$data{0};#“蓝色”打印$data{“0”};#“蓝色”
列表
A类列表在Perl中,无论是数组还是散列都是不同的。您刚刚看到了几个列表:
(“打印”,“这些”,“字符串”,“退出”,“for”,“我”,)(“牛顿”=>“艾萨克”,“爱因斯坦”=>“阿尔伯特”,“达尔文”=>“查尔斯”,)
列表不是变量。列表是短暂的价值可以是分配数组或散列变量。这就是为什么声明数组和散列变量的语法是相同的。在许多情况下,术语“列表”和“数组”可以互换使用,但在同样多的情况下,列表和数组显示出细微不同且极为混乱的行为。
可以。记住=>
只是,
伪装,然后看这个例子:
(“一”,1,“三”,3,“五”,5)(“一”=>1,“三”=>3,“五”=>5)
使用=>
提示其中一个列表是数组声明,另一个是散列声明。但就其本身而言,它们都不是什么声明。它们只是列表。完全相同列表。也:
()
这里甚至没有任何提示。此列表可用于声明空数组或空散列珍珠
口译员显然无法说出这两种方式。一旦理解了Perl的这一奇怪方面,您也会理解为什么以下事实必须是正确的:列表值不能嵌套。试试看:
我的@array=(“苹果”,“香蕉”,(“内部”,“列表”,“多个”,“条目”,),“樱桃”,);
Perl无法知道(“内部”、“列表”、“多个”、“条目”)
应该是内部数组或内部哈希。因此,Perl假定它既不是,也不是将列表扁平化为一个长列表:
打印$array[0];#“苹果”打印$array[1];#“香蕉”打印$array[2];#“内部”打印$array[3];#“列表”打印$array[4];#“几个”打印$array[5];#“条目”打印$array[6];#“樱桃”
无论是否使用胖逗号,情况都一样:
我的%hash=(“啤酒”=>“好”,“香蕉”=>(“绿色”=>“等待”,“yellow”=>“吃”,),);#上面给出了一个警告,因为哈希是使用7元素列表声明的打印$hash{“啤酒”};#“很好”打印$hash{“香蕉”};#“绿色”打印$hash{“wait”};#“黄色”;打印$hash{“吃”};#undef,因此打印“”并引发警告
当然,这确实使将多个数组连接在一起变得容易:
my@bones=(“肱骨”,(“颌骨”,“头骨”),“胫骨”);my@fingers=(“拇指”、“索引”、“中间”、“戒指”、“小”);my@parts=(@骨骼,@手指,(“脚”,“脚趾”),“眼球”,“关节”);打印@部件;
稍后将对此进行详细介绍。
上下文
Perl最显著的特点是它的代码是上下文敏感的.Perl中的每个表达式都在标量上下文或列表上下文中求值,取决于它应该生成标量还是列表。在不知道表达式求值的上下文的情况下,不可能确定它将求值到什么。
标量赋值,例如我的$标量=
在标量上下文中计算其表达式。这里的表达式是“门捷列夫”
:
my$scalar=“门捷列夫”;
数组或散列赋值,例如我的@数组=
或我的%散列=
在列表上下文中计算其表达式。这里的表达式是(“阿尔法”、“贝塔”、“伽玛”、“馅饼”)
(或(“Alpha”=>“Beta”,“Gamma”==>“Pie”)
,两者相当):
my@array=(“阿尔法”,“贝塔”,“伽玛”,“饼图”);my%hash=(“Alpha”=>“Beta”,“Gamma”=>“Pie”);
在列表上下文中计算的标量表达式会自动转换为单元素列表:
my@array=“门捷列夫”;#与'my@array=(“Mendeleev”);'相同
在标量上下文中计算的数组表达式返回数组的长度:
my@array=(“阿尔法”,“贝塔”,“伽玛”,“饼图”);my$scalar=@array;打印$scalar;#"4"
在标量上下文中计算的列表表达式(列表不同于数组,记得吗?)返回的不是列表的长度,而是列表中的最后一个标量:
my$scalar=(“Alpha”、“Beta”、“Gamma”和“Pie”);打印$scalar;#“馅饼”
这个打印
内置函数在列表上下文中计算其所有参数。事实上,打印
接受不受限制的参数列表并逐个打印,这意味着可以使用它直接打印数组:
my@array=(“Alpha”,“Beta”,“Goo”);my$scalar=“-X-”;打印@array;#“AlphaBetaGoo”;打印$scalar,@array,98;#“-X-AlphaBetaGoo98”;
小心。许多Perl表达式和内置函数根据所评估的上下文显示完全不同的行为。最突出的例子是函数颠倒
在列表上下文中,颠倒
将其参数视为列表,并反转该列表。在标量上下文中,颠倒
将整个列表连接在一起,然后将其反转为单个单词。
反向打印“hello world”;#“你好,世界”my$string=reverse“hello world”;打印$string;#“德罗·奥利赫”
可以使用标量
内置功能:
打印标量反转“hello world”;#“德罗·奥利赫”
记住我们是如何使用的标量
早些时候,为了得到数组的长度?
引用和嵌套数据结构
与列表不能包含作为元素的列表一样,数组和哈希不能包含其他数组和哈什作为元素。它们只能包含标量。观察我们尝试时会发生什么:
my@outer=(“太阳”,“水星”,“金星”,undef,“火星”);my@inner=(“地球”、“月亮”);$outer[3]=@内部;打印$outer[3];#"2"
$外部[3]
是标量,因此需要标量值。当您尝试分配数组值时,如@内部
到它,@内部
在标量上下文中计算。这与分配相同标量@内部
,它是数组的长度@内部
,即2。
但是,标量变量可能包含参考到任何变量,包括数组变量或散列变量。这就是如何在Perl中创建更复杂的数据结构。
使用反斜杠创建引用。
my$colour=“靛蓝”;我的$scalarRef=\$colour;
任何时候使用变量名时,都可以只放一些大括号,然后在大括号内放一个参考改为变量。
打印$colour;#“靛蓝”打印$scalarRef;#例如“标尺(0x182c180)”打印${$scalarRef};#“靛蓝”
只要结果不含糊,也可以省略大括号:
打印$$scalarRef;#“靛蓝”
如果引用是对数组或散列变量的引用,则可以使用大括号或更流行的箭头运算符从中获取数据,->
:
my@colors=(“红色”、“橙色”、“黄色”、“绿色”、“蓝色”);我的$arrayRef=\@colors;打印$颜色[0];#直接阵列存取打印${$arrayRef}[0];#使用引用访问数组打印$arrayRef->[0];#完全一样的东西my%原子重量=(“氢”=>1.008,“氦”=>4.003,“锰”=>54.94);我的$hashRef=\%atomicWeights;打印$atomicWeights{“氦”};#直接散列访问打印${$hashRef}{“氦”};#使用引用获取散列打印$hashRef->{“氦”};#完全一样,这很常见
声明数据结构
这里有四个例子,但实际上最后一个是最有用的。
我的%owner1=(“name”=>“圣诞老人”,“DOB”=>“1882-12-25”,);my$owner1Ref=\%owner1;我的%owner2=(“name”=>“米老鼠”,“出生日期”=>“1928-11-18”,);我的$owner2Ref=\%owner2;my@owners=($owner1Ref,$owner2Ref);我的$ownersRef=\@owners;我的%帐户=(“数字”=>“12345678”,“打开”=>“2000-01-01”,“所有者”=>$ownersRef,);
这显然是不必要的,因为您可以将其缩短为:
我的%owner1=(“name”=>“圣诞老人”,“出生日期”=>“1882-12-25”,);我的%owner2=(“name”=>“米老鼠”,“出生日期”=>“1928-11-18”,);my@owners=(\%owner1,\%ower2);我的%帐户=(“数字”=>“12345678”,“打开”=>“2000-01-01”,“所有者”=>\@所有者,);
也可以申报匿名的使用不同符号的数组和散列。对匿名数组使用方括号,对匿名哈希使用大括号。每种情况下返回的值是参考到所讨论的匿名数据结构。仔细观察,结果完全相同%帐户
如上所述:
#大括号表示匿名散列我的$owner1Ref={“name”=>“圣诞老人”,“出生日期”=>“1882-12-25”,};我的$owner2Ref={“name”=>“米老鼠”,“DOB”=>“1928-11-18”,};#方括号表示匿名数组我的$ownersRef=[$owner1Ref,$owner2Ref];我的%帐户=(“数字”=>“12345678”,“打开”=>“2000-01-01”,“所有者”=>$ownersRef,);
或者,简而言之(这是您应该填写的表格事实上在声明内联复杂数据结构时使用):
我的%帐户=(“数字”=>“31415926”,“打开”=>“3000-01-01”,“所有者”=>[{“name”=>“Philip Fry”,“DOB”=>“1974-08-06”,},{“name”=>“Hubert Farnsworth”,“出生日期”=>“2841-04-09”,},],);
从数据结构中获取信息
现在,让我们假设您仍然有%帐户
到处乱踢,但所有其他事情(如果还有其他事情的话)都超出了范围。您可以通过在每种情况下反转相同的过程来打印信息。这里有四个例子,其中最后一个最有用:
我的$ownersRef=$account{“owners”};my@owners=@{$ownersRef};我的$owner1Ref=$owners[0];我的%owner1=%{$owner1Ref};my$owner2Ref=$owners[1];我的%owner2=%{$owner2Ref};打印“帐号”,$Account{“数字”},“\n”;打印“Opened on”,$account{“Opened”},“\n”;打印“联合所有者:\n”;打印“\t”,$owner1{“name”},“(出生”,$所有者1{”DOB“},”)\n“;打印“\t”,$owner2{“name”},“(出生”,$所有者2{”DOB“},”)\n“;
或者,简称:
my@owners=@{$account{“owners”}};我的%owner1=%{$所有者[0]};我的%owner2=%{$所有者[1];打印“账号”,$Account{“number”},“\n”;print“Opened on”,$account{“Opened”},“\n”;打印“联合所有者:\n”;打印“\t”,$owner1{“name”},“(出生”,$所有者1{”DOB“},”)\n“;打印“\t”,$owner2{“name”},“(出生”,$所有者2{”DOB“},”)\n“;
或者使用引用和->
操作员:
我的$ownersRef=$account{“owners”};我的$owner1Ref=$ownersRef->[0];我的$owner2Ref=$ownersRef->[1];打印“帐号”,$Account{“数字”},“\n”;打印“Opened on”,$account{“Opened”},“\n”;打印“联合所有者:\n”;打印“\t”,$owner1Ref->{“name”},“(出生”,$所有者1Ref->{“DOB”}”)\n“;打印“\t”,$owner2Ref->{“name”},“(出生”,$wner2Ref->{“DOB”}”)\n“;
如果我们完全跳过所有中间值:
打印“帐号”,$Account{“数字”},“\n”;打印“Opened on”,$account{“Opened”},“\n”;打印“联合所有者:\n”;打印“\t”,$account{“所有者”}->[0]->{“名称”},“(出生”,$account{”owners“}->[0]->}”DOB“},”)\n“;打印“\t”,$account{“owners”}->[1]->{“name”},“(出生”,$account{”owners“}->[1]->{”DOB“},”)\n“;
如何使用数组引用射击自己的脚
此数组有五个元素:
我的@array1=(1,2,3,4,5);打印@array1;#"12345"
然而,此数组有一个元素(碰巧是对匿名五元素数组的引用):
我的@array2=[1,2,3,4,5];打印@array2;#例如“阵列(0x182c180)”
这个标量是对匿名五元素数组的引用:
我的$array3Ref=[1,2,3,4,5];打印$array3Ref;#例如“阵列(0x22710c0)”打印@{$array3Ref};#"12345"打印@$array3Ref;#"12345"
条件
如果
...elsif公司
...其他的
...
除了拼写埃尔西夫
:
my$word=“反歧视主义”;我的$strlen=长度$word;如果($strlen>=15){打印“”,$word,“”是一个很长的单词“;}elsif(10<=$strlen&&$strlen<15){print“”,$word,“”是一个中等长度的单词“;}其他{打印“”,$word,“”是一个短单词“;}
Perl提供了一个更短的“陈述 如果
条件“强烈建议使用的语法短的声明:
print“'”,$word,“'实际上是巨大的”,如果$strlen>=20;
除非
...其他的
...
我的$温度=20;除非($温度>30){打印$temperature,“摄氏度不是很热”;}其他{打印$temperature,“摄氏度实际上相当热”;}
除非
一般来说,最好像瘟疫一样避免使用积木,因为它们很容易混淆。安“除非
[...其他的
]“可以将块平凡地重构为”如果
[...其他的
]“通过否定条件[或保留条件并交换块]来阻止。幸运的是,没有除非
关键字。
相比之下,强烈建议这样做,因为它很容易阅读:
打印“噢,不,太冷了”,除非$温度>15;
三元运算符
三元运算符?:
允许简单如果
要嵌入到语句中的语句。其规范用法是单数/复数形式:
我的美元收益=48;打印“你获得了”,$gain,“”,($gain==1?“经验点”:“经验点“),“!”;
旁白:在这两种情况下,单数和复数的拼写都是最好的。不要做像下面这样聪明的事情,因为任何搜索代码库来替换单词“tooth”或“toots”的人都不会找到这一行:
我的损失美元=1;打印“You lost”,$lost,“t”,($lost==1?“oo”:“ee”),“th!”;
三元运算符可以嵌套:
我的$eggs=5个;打印“你有”,$eggs==0?“无蛋”:$鸡蛋==1?“鸡蛋”:“一些鸡蛋”;
如果
语句在标量上下文中评估其条件。例如,if(@array)
当且仅当@阵列
包含1个或多个元素。这些元素是什么并不重要,它们可能包含未定义
或其他我们关心的错误值。
循环
有不止一种方法可以做到。
Perl有一个传统的虽然
循环:
我的$i=0;while($i<标量@数组){打印$i,“:”,$array[$i];$i++;}
Perl还提供了直到
关键词:
我的$i=0;直到($i>=标量@数组){打印$i,“:”,$array[$i];$i++;}
这些做
循环是几乎等同于上述内容(如果@阵列
为空):
我的$i=0;做{打印$i,“:”,$array[$i];$i++;}while($i<标量@数组);
和
我的$i=0;做{打印$i,“:”,$array[$i];$i++;}直到($i>=标量@数组);
基本C型对于
循环也可用。请注意我们如何将我的
在内部对于
语句,声明1美元
仅适用于循环范围:
for(my$i=0;$i<标量@数组;$i++){打印$i,“:”,$array[$i];}#$我已经不在这里了,这里要整洁得多。
这种类型的对于
循环被认为是过时的,应尽可能避免使用。列表上的本机迭代要好得多。注意:与PHP不同对于
和foreach公司
关键词是同义词。只需使用看起来最可读的内容:
foreach my$string(@array){打印$string;}
如果您确实需要索引范围运算符 ..
创建匿名整数列表:
每个$i(0..$#数组){打印$i,“:”,$array[$i];}
你不能迭代散列。然而,您可以迭代其键。使用钥匙
内置函数检索包含哈希的所有键的数组。然后使用foreach公司
我们用于阵列的方法:
foreach my$key(keys%科学家){打印$key,“:”,$scientists{$key};}
由于散列没有基本顺序,因此可以按任何顺序返回键。使用分类
内置函数,用于预先按字母顺序对键数组进行排序:
foreach my$key(排序键%科学家){打印$key,“:”,$scientists{$key};}
如果不提供显式迭代器,Perl将使用默认迭代器,$_
.$_
是第一个也是最友好的内置变量:
foreach(@数组){打印$_;}
如果使用默认迭代器,并且只希望在循环中放置一条语句,则可以使用超短循环语法:
打印$_foreach@array;
回路控制
下一个
和最后的
可以用来控制循环的进度。在大多数编程语言中,这些被称为持续
和打破
分别是。我们还可以为任何循环提供标签。按照惯例,标签是用所有资本
.标记好回路后,下一个
和最后的
可能针对该标签。这个例子发现素数低于100:
候选人:我的$候选人(2..100){对于我的$除数(2。。平方英尺$候选人){如果$CANDIDATE%$divisor==0,则为下一个候选日期;}打印$candidate。“是质数”;}
数组函数
就地阵列修改
我们将使用@堆栈
为了证明这些:
my@stack=(“弗雷德”、“艾琳”、“丹尼斯”、“查理”);打印@stack;#“FredEileenDeniseCharlie”
流行音乐
提取并返回数组的最后一个元素。这可以看作是堆栈的顶部:
打印pop@stack;#“查理”打印@stack;#“弗雷德·艾琳·德尼塞”
推
将额外元素附加到数组末尾:
push@stack,“Bob”,“Alice”;打印@stack;#“FredEileenDeniseObAlice”
转移
提取并返回数组的第一个元素:
打印移位@stack;#“弗雷德”打印@stack;#“EileenDeniseBobAlice”
取消移位
在数组的开头插入新元素:
unshift@stack,“Hank”,“Grace”;打印@stack;#“HankGraceEileenDeniseBobAlice”
流行音乐
,推
,转移
和取消移位
都是特殊情况吗剪接
.剪接
删除并返回一个数组切片,并将其替换为其他数组切片:
打印拼接(@stack,1,4,“<<<”,“>>>”);#“GraceEileenDeniseBob”打印@stack;#“汉克·爱丽丝”
从旧阵列创建新阵列
Perl提供了以下函数,这些函数作用于数组以创建其他数组。
这个参加
函数将多个字符串连接为一个:
my@elements=(“锑”、“砷”、“铝”、“硒”);打印@elements;#“锑砷铝硒”打印“@elements”;#“锑砷铝硒”打印连接(“,”,@elements);#锑、砷、铝、硒
在列表上下文中颠倒
函数以相反的顺序返回列表。在标量上下文中,颠倒
将整个列表连接在一起,然后将其反转为单个单词。
反向打印(“Hello”,“World”);#“世界你好”反向打印(“HelloWorld”);#“HelloWorld”(你好世界)打印标量反转(“HelloWorld”);#“dlroWolleH”打印标量反转(“Hello”、“World”);#“dlroWolleH”
这个地图
函数将数组作为输入,并对每个标量应用一个操作$_
在此数组中。然后从结果中构造一个新数组。要执行的操作以大括号内的单个表达式的形式提供:
my@capitals=(“巴吞鲁日”、“印第安纳波利斯”、“哥伦布”、“蒙哥马利”、“海伦娜”、“丹佛”、“博伊西”);打印连接“,”,映射{uc$}@capitals;#“巴顿路,印第安纳波利斯,哥伦布,蒙哥马利,海伦娜,丹佛,博伊斯”
这个格雷普
函数接受一个数组作为输入,并返回一个过滤后的数组作为输出。语法类似于地图
。这一次,为每个标量计算第二个参数$_
在输入数组中。如果返回布尔值true,标量将被放入输出数组,否则不会。
打印连接“,”,grep{length$_==6}@capitals;#“丹佛海伦娜”
显然,结果数组的长度是成功匹配的次数,这意味着您可以使用格雷普
要快速检查数组是否包含元素,请执行以下操作:
打印标量grep{$_eq“Columbus”}@capitals;#"1"
格雷普
和地图
可以组合成列表推导式,这是一个非常强大的功能,在许多其他编程语言中都明显没有。
默认情况下分类
函数返回按词法(字母)顺序排序的输入数组:
my@elevations=(19、1、2、100、3、98、100、1056);打印连接“,”,排序@elevations;# "1, 100, 100, 1056, 19, 2, 3, 98"
然而,与格雷普
和地图
,您可以提供自己的一些代码。排序总是使用两个元素之间的一系列比较来执行。你的区块收到美元
和十亿美元
作为输入,如果美元
是“小于”十亿美元
,如果“相等”则为0,如果美元
“大于”十亿美元
.
这个化学机械抛光
运算符对字符串执行此操作:
打印连接“,”,排序{$acmp$b}@elevations;# "1, 100, 100, 1056, 19, 2, 3, 98"
“宇宙飞船操作员”,<=>
,对数字执行相同操作:
打印连接“,”,排序{$a<=>$b}@elevations;# "1, 2, 3, 19, 98, 100, 100, 1056"
美元
和十亿美元
始终是标量,但它们可以引用非常复杂的对象,很难进行比较。如果需要更多空间进行比较,可以创建单独的子例程并提供其名称:
次级比较器{#大量代码。。。#返回-1、0或1}打印连接“,”,排序比较器@elevations;
你不能这样做格雷普
或地图
操作。
请注意,子程序和块从未显式提供美元
和十亿美元
.喜欢$_
,美元
和十亿美元
实际上是全局变量已填充每次都要比较一对值。
内置功能
到目前为止,您已经看到了至少十几个内置函数:打印
,分类
,地图
,格雷普
,钥匙
,标量
内置函数是Perl最大的优势之一。他们
- 数量众多
- 非常有用
- 是广泛记录
- 语法差异很大,请查看文档
- 有时接受正则表达式作为参数
- 有时接受整个代码块作为参数
- 有时参数之间不需要逗号
- 有时会使用任意数量的逗号分隔参数,有时则不会
- 如果提供的参数太少,有时会填写自己的参数
- 除非在模糊的情况下,否则通常不需要在论点周围加括号
关于内置函数的最佳建议是知道它们的存在浏览文档以备将来参考。如果你正在执行一项任务,感觉它很低级,而且很常见,以至于它以前已经做过多次了,那么它很可能已经完成了。
用户定义的子例程
使用附属的
关键字。与内置函数相比,用户定义的子程序总是接受相同的输入:标量列表。当然,这个列表可能只有一个元素,也可能是空的。单个标量被视为具有单个元素的列表。带有的散列N个元素被视为带有2的列表N个元素。
尽管括号是可选的,但子程序应始终使用括号调用,即使调用时没有参数。这清楚地表明正在进行子例程调用。
进入子例程后,可以使用内置数组变量 @_
。示例:
分连字符{#从数组中提取第一个参数,忽略其他所有参数my$word=shift@_;#过于聪明的列表理解$word=加入“-”,映射{子(substr)$word,$_,1}(0(长度$word)-1);返回$word;}打印连字符(“消灭”);#“e-x-t-e-r-m-i-n-a-t-e”
通过引用进行Perl调用
与几乎所有其他主要编程语言不同,Perl通过引用进行调用。这意味着子程序体中可用的变量或值不是原始的副本。他们是原件。
我的$x=7;再分配{$_[0]=42;}重新分配($x);打印$x;#"42"
如果你尝试一下
重新分配(8);
然后发生错误并停止执行,因为重新分配()
等于
8 = 42;
这显然是胡说八道。
要吸取的教训是,在子程序的主体中,在使用参数之前,应该始终先将其解压缩。
正在解包参数
打开包装有多种方法@_
,但有些人比其他人优越。
示例子例程左侧_页面
下面使用提供的填充字符将字符串填充到所需的长度。(x个
函数将同一字符串的多个副本连接在一行中。)(注意:为了简洁起见,这些子程序都缺少一些基本的错误检查,即确保填充字符只有1个字符,检查宽度是否大于或等于现有字符串的长度,检查是否传递了所有需要的参数。)
左侧_页面
通常按如下方式调用:
打印left_pad(“hello”,10,“+”);#“+++++你好”
-
打开包装@_
逐条输入很有效,但不太好看:
sub-left_pad(副左侧_页){我的$oldString=$_[0];我的$width=$_[1];我的$padChar=$_[2];my$newString=($padChar x($width-length$oldString))$oldString;return$newString;}
-
打开包装@_
通过使用从中删除数据转移
建议最多使用4个参数:
子左_pad{my$oldString=移位@_;my$width=shift@_;my$padChar=shift@_;my$newString=($padChar x($width-length$oldString))$oldString;旧字符串;return$newString;}
如果没有数组提供给转移
功能,然后运行@_
隐式地。这种方法很常见:
sub-left_pad(副左侧_页){my$oldString=移位;my$width=移位;my$padChar=移位;my$newString=($padChar x($width-length$oldString))$oldString;return$newString;}
除了4个参数外,很难跟踪分配到哪里的内容。
-
你可以打开行李@_
使用多个同时标量赋值的一键通。同样,这对于最多4个参数来说是可以的:
sub-left_pad(副左侧_页){my($oldString,$width,$padChar)=@_;my$newString=($padChar x($width-length$oldString))$oldString;return$newString;}
-
对于具有大量参数的子程序,或者某些参数是可选的或不能与其他参数组合使用的子程序来说,最佳实践是要求用户在调用子程序时提供参数散列,然后解压缩@_
回到那个散乱的参数中。对于这种方法,我们的子例程调用看起来有点不同:
打印left_pad(“oldString”=>“pod”,“width”=>10,“padChar”=>”+“);
子程序本身如下所示:
sub-left_pad(副左侧_页){我的%args=@_;my$newString=($args{“padChar”}x($args{“width”}-length$args}“oldString”}))$args{“oldString”};return$newString;返回$newString;}
返回值
与其他Perl表达式一样,子例程调用可能会显示上下文行为。您可以使用万塔雷
函数(应该调用野心家
但没关系)检测子例程在哪个上下文中进行求值,并返回适合该上下文的结果:
子上下文子例程{#呼叫者需要列表。返回列表如果wantarray,返回(“珠穆朗玛峰”、“K2”、“Etna”);#调用方需要标量。返回标量返回3;}my@array=contextualSubroutine();打印@array;#“珠穆朗玛峰K2Etna”my$scalar=contextualSubroutine();打印$scalar;#"3"
系统调用
如果您已经知道以下与Perl无关的事实,请致歉。每次在Windows或Linux系统上(我猜想,在大多数其他系统上)完成一个进程时,它都会以16位结束状态字.最高8位构成返回代码介于0和255之间,0通常表示不合格的成功,其他值表示不同程度的失败。其他8位的检查频率较低,它们“反映了故障模式,如信号死亡和堆芯转储信息”。
您可以使用选择的返回代码(从0到255)退出Perl脚本出口
.
Perl提供了多种方法-在单个调用中-生成子进程,暂停当前脚本直到子进程完成,然后恢复对当前脚本的解释。无论使用哪种方法,您都会立即发现内置标量变量 $?
已使用该子进程终止时返回的状态字填充。只需取16位中最高的8位即可获得返回码:$? >> 8
.
这个系统
函数可用于使用列出的参数调用另一个程序。返回的值系统
与美元?
已填充:
my$rc=system“perl”,“anotherscript.pl”,”foo“,”bar“,”baz“;$rc>>=8;打印$rc;#"37"
或者,您可以使用反勾号``
在命令行中运行实际命令并捕获该命令的标准输出。在标量上下文中,整个输出作为单个字符串返回。在列表上下文中,所有输出作为字符串数组返回,每个字符串代表一行输出。
my$text=`perl anotherscript.pl foo bar baz`;打印$text;#“foobarbaz”
这是一种行为,如果另一个脚本.pl
包含,例如:
使用严格;使用警告;打印@ARGV;37号出口;
文件和文件句柄
标量变量可以包含文件句柄而不是数字/string/reference或未定义
。文件句柄本质上是对特定文件中特定位置的引用。
使用打开
将标量变量转换为文件句柄。打开
必须提供模式.模式<
表示我们希望打开文件以从中读取:
my$f=“text.txt”;my$result=打开我的$fh,“<”,$f;if(!$result){死亡“无法打开”$f.“”用于阅读,因为:“.$!;}
如果成功,打开
返回一个真值。否则,它将返回false,并在内置变量中填充错误消息$!
如上所示,您应该始终检查打开
操作已成功完成。这种检查相当乏味,一个常见的习惯用法是:
open(my$fh,“<”,$f)|| die“Couldn not open”(无法打开)$f.“”用于阅读,因为:“.$!;
注意需要在打开
调用的参数。
要从文件句柄读取一行文本,请使用读行
内置函数。读行
返回一整行文本,并在其末尾保留换行符(可能文件的最后一行除外),或未定义
如果你已经到了文件的末尾。
而(1){my$line=readline$fh;最后一个,除非定义$line;#处理生产线。。。}
要截断可能的尾部换行符,请使用咀嚼
:
chomp$line;
请注意咀嚼
作用于$行
到位。$line=chomp$line
可能不是你想要的。
您还可以使用电动势
要检测是否已到达文件末尾,请执行以下操作:
而(!eof$fh){my$line=readline$fh;#处理$line。。。}
这也适用于:
while(我的$line=readline$fh){#处理$line。。。}
你会认为如果$行
原来是单字符字符串"0"
,这是假的。然而,在这个特定的例子中,Perl神奇地将第一行代码while(已定义(my$line=readline$fh)){
然而,这确实会打破:
我的$x=7;while($x==7和my$line=readline$fh){打印“行”,转储程序($line);}
Perl还提供了<>
运算符,它是的同义词读行
:
while(我的$line=<$fh>){#处理$line。。。}
甚至:
同时(<$fh>){#处理$_。。。}
写入文件首先需要以不同的模式打开它。模式>
表示我们希望打开文件以写入(>
如果目标文件已经存在并且包含内容,则将清除目标文件的内容。要仅附加到现有文件,请使用mode>>
.)然后,只需为打印
功能。
open(my$fh2,“>”,$f)|| die“无法打开”$f.“”用于写作,因为:“.$!;打印$fh2“老鹰已经离开巢穴”;
请注意,中间没有逗号2美元
以及下一个论点。
当文件句柄超出范围时,它们实际上会自动关闭,否则:
关闭2美元;关闭$fh;
三个文件句柄作为全局常量存在:标准DIN
,STDOUT公司
和STDERR公司
。这些在脚本启动时自动打开。要读取单行用户输入:
我的$line=<STDIN>;
要等待用户按Enter键:
<标准DIN>;
打电话<>
没有文件句柄时从中读取数据标准DIN
,或者在调用Perl脚本时从参数中命名的任何文件中获取。
正如你可能已经收集到的,打印
打印到STDOUT公司
默认情况下,如果没有命名文件句柄。
文件测试
功能-e(电子)
是一个内置函数,用于测试命名文件是否存在。
打印“what”,除非-e“/usr/bin/perl”;
功能-d日
是一个内置函数,用于测试命名文件是否为目录。
功能-(f)
是一个内置函数,用于测试命名文件是否为普通文件。
这只是其中的三个一大类函数表单的-X(X)
哪里X(X)
是一些小写或大写字母。这些函数称为文件测试。注意前面的减号。在谷歌查询中,减号表示排除包含此搜索词的结果。这使得谷歌很难进行文件测试!只需搜索“perl文件测试”即可。
正则表达式
正则表达式出现在除Perl之外的许多语言和工具中。Perl的核心正则表达式语法与其他地方基本相同,但Perl的满的正则表达式功能非常复杂,难以理解。我能给你的最好建议是尽可能避免这种复杂性。
匹配操作使用=~米//
。在标量上下文中,=~米//
成功时返回true,失败时返回false。
my$string=“Hello world”;if($string=~m/(\w+)\s+(\w+)/){打印“成功”;}
括号执行子匹配。成功执行匹配操作后,子匹配将填充到内置变量中$1
,$2
,$3
, ...:
打印$1;#“你好”打印$2;#“世界”
在列表上下文中,=~米//
收益$1
,$2
, ... 作为列表。
我的$string=“无色的绿色想法疯狂入睡”;my@matchs=$string=~m/(\w+)\s+((\w+)\s+(\w+))\s+(\w+)\s+(\w+)/;打印连接“,”,映射{“”.$_.“”}@matches;#打印“无色”、“绿色理念”、“环保”、“创意”、“睡眠”、“疯狂”
替换操作使用=~秒///
.
my$string=“早上好,世界”;$string=~s/world/越南/;打印$string;#“早上好,越南”
请注意$string($string)
已更改。您必须在=%s///
操作。如果你传递一个文本字符串,你会得到一个错误。
这个/克
标志表示“全局匹配”。
在标量上下文中,每个=~m//g
call在前一个匹配项之后查找另一个匹配,成功时返回true,失败时返回false。您可以访问$1
然后以通常的方式继续。例如:
my$string=“一吨羽毛或一吨砖块”;while($string=~m/(\w+)/g){打印“”$1.“\n”;}
在列表上下文中=~m//g
调用一次返回所有匹配项。
my@matches=$string=~m/(\w+)/g;打印连接“,”,映射{“”.$_.“”}@matches;
安=~s///g
call执行全局搜索/替换并返回匹配的数量。在这里,我们用字母“r”替换所有元音。
#在没有/g的情况下尝试一次。$string=~s/[aeiou]/r/;打印$string;#“一吨羽毛或一吨砖块”#再一次。$string=~s/[aeiou]/r/;打印$string;#“一堆羽毛或一吨砖块”#然后使用/g完成其余操作$string=~s/[aeiou]/r/g;打印$string,“\n”;#“r trnnr rf frrthrrs rr r trnnr rf brrcks”
这个/我
标志使匹配和替换区分大小写。
这个/x个
flag允许正则表达式包含空白(例如换行符)和注释。
“你好,世界”=~m/(\w+)#一个或多个单词字符[]#单个文字空间,存储在字符类中world#literal“world”/x;#返回true
模块和包
在Perl中,模块和包是不同的。
模块
A类模块是一个下午点
您可以使用的文件包括在另一个Perl文件(脚本或模块)中。模块是一个文本文件,其语法与.pl文件
Perl脚本。示例模块可能位于C: \foo\bar\baz\Demo\StringUtils.pm
或/foo/bar/baz/Demo/StringUtils.pm文件
,内容如下:
使用严格;使用警告;亚僵尸化{my$word=shift@_;$word=~s/[aeiou]/r/g;返回$word;}返回1;
因为模块在加载时是从上到下执行的,所以需要在末尾返回一个真值,以表明它已成功加载。
为了让Perl解释器能够找到它们,应该在环境变量中列出包含Perl模块的目录第15页
打电话之前珍珠
。列出包含模块的根目录,不要列出模块目录或模块本身:
设置PERL5LIB=“C:\foo\bar\baz;%PERL5LINB%”
或
export PERL5LIB=“/foo/bar/baz:$PERL5LIB”
创建Perl模块后珍珠
知道在哪里查找它,您可以使用要求
在Perl脚本中搜索和执行它的内置函数。例如,呼叫需要演示::StringUtils
使Perl解释器搜索中列出的每个目录PERL5LIB公司
反过来,查找名为演示/StringUtils.pm
执行模块后,在那里定义的子例程突然可用于主脚本。我们的示例脚本可能被调用main.pl(主pl)
内容如下:
使用严格;使用警告;需要演示::StringUtils;打印zombify(“我想要大脑”);#“r wrnt brrrns”
注意双冒号的用法::
作为目录分隔符。
现在出现了一个问题:如果main.pl(主pl)
包含许多要求
调用,这样加载的每个模块都包含更多要求
调用,则可能很难跟踪zombify()
子程序。这个问题的解决方案是使用包。
包装
A类包裹可以在其中声明子例程的命名空间。您声明的任何子例程都在当前包中隐式声明。在执行开始时,您处于主要的
包,但可以使用包装
内置功能:
使用严格;使用警告;子子程序{打印“宇宙”;}包装食品:土豆;#无碰撞:子子程序{印刷“金德沃德”;}
注意双冒号的用法::
作为命名空间分隔符。
每次调用子例程时,都会隐式调用当前包中的子例程。或者,您可以显式地提供一个包。看看如果我们继续上面的脚本会发生什么:
子例程();#“金德华”main::子例程();#“宇宙”食物::土豆::subroutine();#“金德华”
因此,上述问题的逻辑解决方案是修改C: \foo\bar\baz\Demo\StringUtils.pm
或/foo/bar/baz/Demo/StringUtils.pm文件
阅读:
使用严格;使用警告;软件包演示::StringUtils;亚僵尸化{my$word=shift@_;$word=~s/[aeiou]/r/g;返回$word;}返回1;
并修改main.pl(主pl)
阅读:
使用严格;使用警告;需要演示::StringUtils;打印演示::StringUtils::zombify(“我想要大脑”);#“r wrnt brrrns”
现在仔细阅读下面的内容。
包和模块是Perl编程语言的两个完全独立的特性。它们都使用相同的双冒号分隔符,这是一个巨大的转移注意力的问题。在脚本或模块的过程中,可以多次切换包,也可以在多个文件的多个位置使用相同的包声明。打电话需要Foo::Bar
不会查找并加载带有包装Foo::Bar
声明,也不一定要在Foo::酒吧
命名空间。打电话需要Foo::Bar
只加载一个名为食品/酒吧.pm
,无需任何它内部的包声明类型,实际上可能声明包Baz::Qux
据你所知,这里面还有其他的胡说八道。
同样,子例程调用Baz::Qux::processThis()
不一定在名为巴兹/库克.pm
它本可以被宣布随便什么地方.
将这两个概念分开是Perl最愚蠢的特性之一,将它们作为单独的概念处理总是会导致混乱、令人恼火的代码。幸运的是,大多数Perl程序员都遵守以下两条定律:
- Perl脚本(
.pl文件
文件)必须始终包含零包裹
声明。
- Perl模块(
下午点
文件)必须始终包含一个包裹
声明,与它的名称和位置完全对应。例如模块演示/StringUtils.pm
必须以开头包演示::StringUtils
.
因此,在实践中,您会发现大多数“包”和“模块”都是由可靠的第三方生产的可以可以互换地看待和提及。然而,重要的是你不要认为这是理所当然的,因为有一天你将满足一个疯子产生的代码。
面向对象的Perl
Perl不是一种很好的面向对象编程语言。Perl的OO功能是在事实发生后移植的,这一点可以看出。
一个简单的例子让这一点更加清楚。示例模块动画.pm
包含类动物
内容如下:
使用严格;使用警告;包装动物;分餐{#第一个参数始终是采取行动的对象。我的$self=轮班@_;给我的$食物(@_){if($self->can_eat($food)){打印“Eating”,$food;}其他{打印“不能吃”,$food;}}}#为了便于争论,假设动物可以吃任何东西。子caneat(_E){返回1;}返回1;
我们可以这样使用这个类:
需要动物;我的$动物={“腿”=>4,“color”=>“棕色”,};#$animal是一个普通的散列引用打印参考$animal;#“哈什”祝福$animal,“animal”;#现在它是“动物”类的对象打印参考$animal;#“动物”
注意:从字面上看,任何引用都可以被祝福进入任何类。您需要确保(1)referent实际上可以用作该类的实例,以及(2)所讨论的类存在并已被加载。
您仍然可以按常规方式使用原始散列:
打印“Animal has”,$Animal->{“legs”},“leg(s)”;
但您现在也可以使用相同的->
操作员,就像这样:
$动物->吃(“昆虫”、“咖喱”、“桉树”);
最后一次调用相当于动物::吃($动物,“昆虫”,“咖喱”,“桉树”)
.
建造师
构造函数是返回新对象的类方法。如果你想要一个,就申报一个。你可以用任何你喜欢的名字。对于类方法,传递的第一个参数不是对象,而是类名。在这种情况下,“动物”
:
使用严格;使用警告;包装动物;sub新{my$class=shift@_;返回祝福{“legs”=>4,“colour”=>“brown”},$class;}# ...等。
然后按如下方式使用:
my$animal=动物->new();
继承
要创建从父类继承的类,请使用使用父级
。假设我们子类化了动物
具有考拉
,位于科拉帕.pm
:
使用严格;使用警告;包装考拉;#从动物身上继承使用父母(“动物”);#覆盖一个方法子caneat(_E){my$self=shift@_;#未使用。你可以在这里输入“shift@_;”我的$food=shift@;return$food eq“桉树”;}返回1;
以及一些示例代码:
使用严格;使用警告;需要考拉;my$koala=koala->new();$考拉->吃(“昆虫”、“咖喱”、“桉树”);#只吃桉树
最后一个方法调用尝试调用考拉::吃($考拉,“昆虫”,“咖喱”,“桉树”)
,但它是一个子例程eat()
未在中定义考拉
包裹。然而,因为考拉
有父类动物
,Perl解释器尝试调用动物::吃($考拉,“昆虫”,“咖喱”,“桉树”)
相反,这是有效的。注意类是如何动物
由自动加载科拉帕.pm
.
自使用父级
Perl接受父类名称列表,支持多重继承,具有所有的优点和缺点。
开始
阻碍
A类开始
块一旦执行珍珠
已完成对该块的解析,甚至在它解析文件的其余部分之前。它在执行时被忽略:
使用严格;使用警告;打印“这是第二次打印”;开始{print“首先打印此内容”;}打印“这第三次打印”;
A类开始
块总是先执行。如果创建多个开始
块(没有),当编译器遇到它们时,它们将按从上到下的顺序执行。A类开始
块总是首先执行,即使它被放置在脚本的中间(不要这样做)或末尾(或这样)。不要弄乱代码的自然顺序。放置开始
一开始就有几个街区!
A类开始
块被解析后立即执行。一旦完成,解析结束时的简历开始
块。只有在解析了整个脚本或模块之后开始
执行的块。
严格使用;使用警告;print“此‘print’语句解析成功但从未执行”;开始{打印“This gets printed first”;}打印“这也是成功解析但从未执行的”;……因为e4h8v3oitv8h4o8gch3o84c3下面有一个巨大的解析错误。
因为它们是在编译时执行的开始
放置在条件块内的块将仍然首先执行,即使条件的计算结果为false,并且尽管条件尚未评估事实上可能永远不会被评估.
如果(0){开始{打印“这一定会被打印出来”;}打印“即使这不会”;}
不要把开始
条件性块!如果要在编译时有条件地执行某些操作,则需要将条件里面这个开始
块:
开始{if($条件){#等。}}
使用
可以。现在您已经了解了包、模块、类方法和开始
方块,我可以解释非常常见的使用
功能。
以下三项声明:
使用Caterpillar(“爬行”、“化蛹”);使用Caterpillar();使用Caterpillar;
分别相当于:
开始{需要Caterpillar;Caterpillar->导入(“爬行”、“化蛹”);}开始{需要Caterpillar;}开始{需要Caterpillar;Caterpillar->导入();}
- 不,这三个例子的顺序没有错。只是Perl很蠢。
- A类
使用
呼叫是伪装的开始
块。同样的警告也适用。使用
语句必须始终放在文件的顶部,并且从不包含条件句.
导入()
不是内置的Perl函数。它是一个用户定义的类方法。责任在于毛虫
要定义或继承的包导入()
理论上,该方法可以接受任何东西作为参数,并对这些参数执行任何操作。使用Caterpillar;
可以做任何事。请参阅以下文档毛虫.pm
来找出到底会发生什么。
- 注意如何
需要Caterpillar
加载a模块命名毛虫.pm
,而Caterpillar->导入()
调用导入()
在毛虫
包装。让我们希望模块和包一致!
出口商
定义导入()
方法是从出口商模块。Exporter是一个核心模块事实上的Perl编程语言的核心特性。出口商实施导入()
,传入的参数列表被解释为子例程名称列表。当子程序导入()
ed,它既可以在当前包中使用,也可以在自己的原始包中使用。
通过示例,这个概念最容易掌握。这是什么毛虫.pm
看起来像:
使用严格;使用警告;卡特彼勒成套设备;#从导出器继承使用父项(“导出器”);sub-craw{打印“英寸”;}sub-eat{打印“chomp chomp”;}亚蛹{打印“bloop bloop”;}我们的@EXPORT_OK=(“爬行”,“吃”);返回1;
包变量@导出_确定
应包含子例程名称列表。
然后,另一段代码可能导入()
这些子例程的名称,通常使用使用
声明:
使用严格;使用警告;使用Caterpillar(“爬行”);爬行();#“英寸-英寸”
在这种情况下,当前程序包是主要的
,所以爬行()
呼叫实际上是呼叫main::爬行()
,(因为它是导入的)映射到Caterpillar::爬行()
.
注:无论@导出_确定
,每种方法都可以称为“长手法”:
使用严格;使用警告;使用Caterpillar();#未命名子例程,未进行import()调用#然而。。。卡特彼勒::爬行();#“英寸-英寸”卡特彼勒::eat();#“狼吞虎咽”卡特彼勒::pulate();#“bloop bloop”
Perl没有私有方法。通常,用于私有用途的方法使用前导下划线或两个下划线命名。
@出口
Exporter模块还定义了一个名为@出口
,也可以用子例程名称列表填充。
使用严格;使用警告;卡特彼勒成套设备;#从导出器继承使用父项(“导出器”);sub-craw{打印“英寸”;}sub-eat{打印“chomp chomp”;}化蛹{打印“bloop bloop”;}我们的@EXPORT=(“爬行”、“吃”、“化蛹”);返回1;
中命名的子例程@出口
如果导入()
调用时根本没有参数,这就是这里发生的情况:
使用严格;使用警告;使用Caterpillar;#调用不带参数的import()爬行();#“英寸-英寸”eat();#“狼吞虎咽”pupate();#“bloop bloop”
但请注意,我们是如何回到这样一种情况的,在没有其他线索的情况下,可能很难判断出在哪里爬行()
最初定义为。这个故事的寓意是双重的:
创建使用Exporter的模块时,切勿使用@出口
默认情况下导出子例程。始终让用户调用子程序“手动”或导入()
它们显式地(使用例如。使用Caterpillar(“爬行”)
,这是一个很好的线索毛虫.pm
用于定义爬行()
).
什么时候?使用
在使用Exporter的模块中,始终显式地命名要执行的子例程导入()
.如果你不想导入()
任何子程序,如果希望直接引用它们,必须提供一个明确的空列表:使用Caterpillar()
.
随笔杂记
-
核心模块数据::自卸车可用于将任意标量输出到屏幕。这是一个基本的调试工具。
-
有一种替代语法,qw{}
,用于声明数组。这经常出现在使用
声明:
使用帐户qw{create-open-close-spend-delete};
有许多其他类似报价的运营商.
-
在=~米//
和=~秒///
操作时,可以使用大括号而不是斜杠作为正则表达式分隔符。如果正则表达式包含大量斜杠,这将非常有用,否则需要使用反斜杠进行转义。例如,=~m{//}
匹配三个正斜杠,并且=~s{^https?://}{}
删除URL的协议部分。
-
Perl确实有常量
现在,这些都不受欢迎,但并非总是如此。常量实际上只是带有省略括号的子例程调用。
-
有时人们会省略散列键周围的引号$hash{key}
而不是$hash{“密钥”}
他们可以逃脱惩罚,因为在这种情况下钥匙
作为字符串出现“密钥”
,与子例程调用相反键()
.
-
如果您看到一块未格式化的代码用双V形分隔符包装,如<<EOF
,对于谷歌来说,“here-doc”是一个神奇的词。
-
警告!许多内置函数可以在不带参数的情况下调用,让他们动手术$_
相反希望这将有助于您了解以下阵型:
打印foreach@array;
和
foreach(@array){下一个,除非另有规定;}
我不喜欢这种形式,因为它会在重构时导致问题。
这是两个半小时。