Perl導入代碼文件

從函數複用開始:eval和do執行perl文件

當咱們定義了一個功能比較通用的子程序,好比獲取數值的絕對值。想要處處使用這個子程序,就得不斷複製、粘貼這段絕對值函數的定義文本。顯然,這是不太理想的方式。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

eval語句導入文件

能夠在其它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語句臨時編譯這個文件,它將在當前程序(不管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保持跟蹤。

require導入文件

想象一下,若是在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相關的幾點特性:

  • require的本質上do語句,do語句的本質是eval
  • require是在程序運行時執行的
  • 所導入文件中的任何語法錯誤都回直接die,所以能夠省略die $@ if $@
  • require還能用於要求版本號,例如:require 5.010;
  • 在使用require時,若是使用的是裸詞,例如require Foo::Bar;,將搜索@INC中的Foo/Bar.pm文件
  • 若是使用的不是裸詞,以下。若是是絕對路徑,則按照絕對路徑查找,若是是相對路徑,將從@INC路徑下直接搜索Foo::Bar文件,顯然文件通常不會這樣命名,將會發出警告
    • require "Foo::Bar";:(雙引號的存在)
    • require $class;其中$class="Foo::Bar"
    • require 'myperl.pm';
相關文章
相關標籤/搜索