Я должен определить некоторые модули и использовать их всех в том же файле. Нет, я не могу изменить требование.
Я хотел бы сделать что-то как следующее:
{
package FooObj;
sub new { ... }
sub add_data { ... }
}
{
package BarObj;
use FooObj;
sub new {
...
# BarObj "has a" FooObj
my $self = ( myFoo => FooObj->new() );
...
}
sub some_method { ... }
}
my $bar = BarObj->new();
Однако это приводит к сообщению:
Не может определить местоположение FooObj.pm в @INC...
BEGIN перестала работать...
Как я заставляю это работать?
Бросьте использовать
. Серьезно.
use
говорит perl прочитать код из другого файла, что вам не нужно делать, потому что код находится в том же файле.
Если я не пытаюсь создать приватный пакет, о котором никто не должен знать, я помещаю один пакет в один файл. Это решает проблему. Но давайте поместим их в один файл.
Функция use загружает файл и вызывает метод import
в этом пакете. На самом деле только случайно его аргумент выглядит как имя модуля. Он ищет файл. Если файла там нет, он вылетает.
Можно сделать так, где BarObj
предполагает, что FooObj
уже есть:
{
package FooObj;
sub new { bless { _count => 0 }, $_[0] }
sub add_data { $_[0]->{_count}++ }
}
{
package BarObj;
use Data::Dumper;
sub new {
bless { myFoo => FooObj->new }, $_[0];
}
sub foo { $_[0]->{myFoo} }
sub some_method { print Dumper( $_[0] ) }
}
my $bar = BarObj->new;
$bar->some_method;
Если вам нужно взаимодействовать с пакетом (а это все, чем он является: не модуль и не объект), вам просто нужно, чтобы он был определен до того, как вы захотите его использовать. Если вам нужно что-то импортировать, вы можете вызвать import
напрямую:
FooObj->import( ... );
Предположим, есть что-то из FooObj
, что вы хотите импортировать (но не наследовать! Вы вызываете import
напрямую без загрузки;
{
package FooObj;
use Data::Dumper;
sub new { bless { _count => 0 }, $_[0] }
sub add_data { $_[0]->{_count}++ }
use Exporter qw(import);
our @EXPORT = qw(dumper);
sub dumper { print Dumper( $_[0] ) }
}
{
package BarObj;
FooObj->import;
sub new {
bless { myFoo => FooObj->new }, $_[0];
}
sub foo { $_[0]->{myFoo} }
# dumper mixin, not inherited.
sub some_method { dumper( $_[0] ) }
}
my $bar = BarObj->new;
$bar->some_method;
По соглашению мы помещаем один пакет в один файл и называем их одинаково, но это просто для удобства. Вы можете поместить несколько пакетов в один файл. Поскольку они уже загружены, вам не нужно использовать , использовать
.
Вам также не нужно создавать специальную область видимости для пакетов, так как об этом позаботится ключевое слово package. Использование фигурных скобок помогает определить область видимости наших
переменных. Таким образом, вам не обязательно нужны эти скобы, но это хорошая идея.
use
использует соглашение об именах пакетов, чтобы найти подходящий файл для загрузки. Ключевое слово package
внутри модуля определяет пространство имен. А функции импорта обрабатывают загрузку пакета (обычно унаследованного от Exporter).
#!/usr/bin/perl
use strict;
use warnings;
package FooObj;
sub new
{
my $this = shift;
my $class = ref($this) || $this;
my $self = {};
bless $self, $class;
$self->initialize();
return $self;
}
sub initialize { }
sub add_data { }
package BarObj;
#use FooObj; <-- not needed.
sub new
{
my $this = shift;
my $class = ref($this) || $this;
my $self = { myFoo => FooObj->new() };
bless $self, $class;
$self->initialize();
return $self;
}
sub initialize { }
sub some_method { }
sub myFoo { return $_[0]->{myFoo} }
package main;
use Test::More;
my $bar = BarObj->new();
isa_ok( $bar, 'BarObj', "bar is a BarObj" );
isa_ok( $bar->myFoo, 'FooObj', "bar->myFoo is a FooObj" );
done_testing();
__DATA__
ok 1 - bar is a BarObj isa BarObj
ok 2 - bar->myFoo is a FooObj isa FooObj
1..2