當咱們定義了一個功能比較通用的子程序,好比獲取數值的絕對值。想要處處使用這個子程序,就得不斷複製、粘貼這段絕對值函數的定義文本。顯然,這是不太理想的方式。app
因而,就將包含這個子程序的代碼放進一個perl文件,而後經過特殊的語法去導入這個文件。函數
例如,文件sum.pm包含一個sum子程序,該子程序返回參數相加之和。測試
#!/usr/bin/env perl # 注意,這裏爲了測試,沒加use strict sub sum { my $sum; $sum = map { $_ + $sum } $@ $name; } $name="longshuai"; # 全局變量屬性
其中.pm
後綴表示perl module。在perl 4的時候,使用的是.pl
後綴,表明的是perl library。但如今,模塊、包都使用.pm
替代,而.pl
主要表明perl程序。ui
能夠在其它perl文件中(如eval.pm)經過eval語句臨時編譯這個文件(sum.pm)中的語句。只不過在eval以前,須要先將sum.pm文件中的內容讀取:code
#!/usr/bin/env perl # use strict; use warnings; use 5.010; open my $fh,"<","sum.pm" or die "Can't open file: $!"; undef $/; my $sum_code=<$fh>; # 讀取代碼保存到變量中 close $fh; eval $sum_code; # eval評估編譯這段代碼,並執行 die $@ if $@; my $sum=sum(1,2,3); # 引用來自sum.pm的函數 say $sum;
上面的代碼會報錯。由於eval $sum_code
是未來自sum.pm中的代碼放在當前文件中臨時進行編譯,這段來自sum.pm的代碼已經屬於本文件。就等價於:hash
eval CODE;
因此,來自sum.pm中的全局屬性$name
在當前文件的use strict
編譯指示下將引起錯誤。因此,得將sum.pm內容中的$name
去掉,或者加上my修飾。編譯
eval中來自sum.pm的代碼將能訪問它所在代碼塊的詞法變量。class
也能夠經過do語句臨時編譯這個文件,它將在當前程序(不管do語句是不是在代碼塊中)引入編譯的結果(但除了子程序外的其它屬性,因爲通常會加上use strict
,而致使爲未聲明的變量不可以使用,間接地,所導入的文件中的變量$name
將失效)。require
#!/usr/bin/env perl # use strict; use warnings; use 5.010; { do 'sum.pm'; die $@ if $@; my $sum=sum(1,2,3); say $sum; # say $name; # 由於use strict的存在,而報錯 } say sum(2,3,4); # 出了語句塊,函數仍有效
注意,do語句是在當前文件中引入變異結果,而不是當前代碼塊。變量
do導入文件時若是使用的是相對路徑(如do 'sum1.pm'
),將搜索@INC
,搜索到後將更新%INC
保持跟蹤。
想象一下,若是在myperl.pm中使用do一次性導入兩個文件sum1.pm、sum2.pm:
do 'sum1.pm'; die $@ if $@; do 'sum2.pm'; die $@ if $@;
假設sum2.pm中也用了do語句導入sum1.pm,這樣將會在myperl.pm中屢次導入sum1.pm。其實第二次導入是多餘的,儘管兩次導入的內容是徹底一致的,並且若是開啓了use warnings
,將會發出警告。
使用require語句能夠解決這樣重定義問題。
require '/perlapp/sum1.pm'; # 要給定正確的路徑 require '/perlapp/sum2.pm';
require會在hash結構%INC
中跟蹤已經成功導入的文件,即便sum2.pm中也有require 'sum1.pm'
語句。
爲了跟蹤是否曾經導入成功,要求所導入的文件最後要返回一個true,通常都會使用數值1做爲所導入文件代碼的結尾。並不是必定是1,也能夠是其它值,只要能表示最後這個文件是成功的就行。
例如,sum1.pm中:
#!/usr/bin/env perl use strict; use warnings; use 5.010; sub sum { my $sum; $sum = map { $_ + $sum } $@ $name; } 1; # 最後一行用1表示成功
如下是require相關的幾點特性:
die $@ if $@
require 5.010;
require Foo::Bar;
,將搜索@INC
中的Foo/Bar.pm文件@INC
路徑下直接搜索Foo::Bar
文件,顯然文件通常不會這樣命名,將會發出警告
require "Foo::Bar";
:(雙引號的存在)require $class;
其中$class="Foo::Bar"
require 'myperl.pm';