- 2005-12-05 (月)
- Perl
以前飲み会で、会社の先輩と「use と require の違いってなんじゃ?」てな話をした際、知識不足ゆえうまく答えが出せなかったのですが、Programming Perl 等をちょろちょろ読み始めた今なら、ちょっとはマシな回答が出来る気がした /w のでまとめてみました。
use と require の違い
perldoc を始め、色々なサイトや書籍でも既に述べられているとおり、
use はコンパイル時に評価される - module load happens at comile time.
require は実行時に評価される - module load happens at run time.
が明確な違いになります。また、 perldoc(*) によると use は実際には以下のコードを実行するのと同等だそうです :
BEGIN {
require MODULE;
MODULE->import(LIST);
}
特殊ブロック BEGIN で括る = コンパイル時に評価される事に加え、
use はロードしたモジュールの import 関数を実行している
点も明確な違いになりますね。では以上2点の違いをもう少し具体的に説明してみます。
*perldoc での記述箇所例) $ perldoc perlmod → Perl Modules の章 (/use Module でsearchするべし)
メモリロードのタイミングが違う
use の場合はコード中のどんな場所に宣言があろうが、すべての対象モジュールを、コンパイル時にメモリにロードします。片や require の方は、実際に require 文が実行されるタイミングになって、初めて対象モジュールをメモリにロードします。以下サンプルコード:
if($needs == 1){
require "Hoge.pm"; # $needsが1だった場合のみメモリにロードされる
use Hoge; # $needsの値に関係なく、コンパイル時にメモリにロードされる
}
てな違いになります。require は条件文で true になった場合にロードされるのに対し、use の場合は条件文に入る前から既にロードされている事になります。この違いを理解したうえで、うまく使い分ければ、例えば
必要性が実行時まで不明確なモジュールは require で読み込む事により、ソース全体の起動時のオーバーヘッドを減らす事が可能
だったり、
子プロセスを fork していくようなコードの場合は use を使うことにより、効率的なメモリ使用による全体効率の向上が可能
だったりします。※後者の話は second life 氏の LLDN 記事や naoya 氏の Perl の use と mod_perl、あと LLDN 感想ちょっと。 記事辺りで miyagawa氏を交えて詳しく語られています。
特殊ブロックの挙動が違う
モジュールの中では、コンパイル時に実行される特殊なブロック - BEGIN, CHECK, INIT - を記述しておくことが出来ますが、use と require ではこれらの実行タイミング、及び実行有無がそれぞれ異なります。
use の場合
- BEGIN
- CHECK
- INIT --- 3種すべてコンパイル時に実行
require の場合
- BEGIN - メモリロードされたタイミングで実行
- CHECK - 無視される
- INIT - 無視される
以下、これらブロックが記述されたモジュール UseReq を使ったサンプルコードを書いてみました:
UseReq.pm
package UseReq;
use strict;
INIT { print "UseReq init\n" }
BEGIN { print "UseReq begin\n" }
CHECK { print "UseReq check\n" }
sub hoge { print "hoge called\n" }
1;
use の場合
#!/usr/bin/perl
print "--- script start ---\n";
use UseReq;
UseReq::hoge(); ### 実行結果 ##### $ ./use.pl UseReq begin
UseReq check
UseReq init
--- script start ---
hoge called
各種特殊ブロック実行 → コード実行 の順番になっています。
reqiure の場合
#!/usr/bin/perl
print "--- script start ---\n";
require 'UseReq.pm';
UseReq::hoge(); ### 実行結果 ##### $ ./req.pl --- script start ---
UseReq begin
hoge called
require の場合、INIT と CHECK ブロックは実行されず、かつ 全体コード実行 → require 評価時点で BEGIN 実行 の順番になっています。
※なお END, DESTROY ブロックについては違いは無い模様。
Exporter の利用可・不可の違い
2つ目の違いとして挙げた
use はロードしたモジュールの import 関数を実行している
点について、use と require の違いがもっとも判りやすい例が Exporter だと思います。Exporter モジュールが何をするものかは perldoc を参照してもらうとして、両者の違いは何かと言うと、
use → Exporter による関数インポートが利用可能
require → 利用不可
という事になります(単純)。サンプルコードでこの事を表すと以下のようになります:
UseReq.pm
package UseReq;
use base Exporter;
use strict;
our @EXPORT_OK = qw(hoge);
sub hoge { print "hoge called\n" }
1;
use の場合
#!/usr/bin/perl use UseReq qw(hoge);
hoge();
### 実行結果 ### $ ./use.pl hoge called
require の場合
#!/usr/bin/perl
require 'UseReq.pm';
hoge();
### 実行結果 ###
$ ./req.pl
Undefined subroutine &main::hoge called at ./usereq.pl line 3.
require の場合だと Exporter モジュールの import 関数が自動実行されない為、関数インポートができていませんね。require しつつ Exporter を使いたい場合は、require 宣言の直後に自分で import 関数を実行する必要があります:
#!/usr/bin/perl
require 'UseReq.pm';
UseReq->import('hoge');
hoge();
### 実行結果 ###
$ ./req.pl
hoge called
以上、長くなってしまいましたが、こんな感じにまとめてみました。... ゆうごさん (先輩) どうでしょうか?
- Newer: グーグル流経営10のルール - Google: Ten Golden Rules
- Older: Attribute::Handlers と use encoding 'utf8' を併用した際の妖しい挙動