Ответ 1
Снимите use
. Серьезно.
use
указывает perl читать в коде из другого файла, что вам не нужно делать, потому что код находится в одном файле.
Мне нужно определить некоторые модули и использовать их все в одном файле. Нет, я не могу изменить это требование.
Я хотел бы сделать что-то вроде следующего:
{
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
. Серьезно.
use
указывает perl читать в коде из другого файла, что вам не нужно делать, потому что код находится в одном файле.
Если я не пытаюсь создать закрытый пакет, о котором никто не должен знать, я помещаю один пакет в файл. Это решает проблему. Но пусть они помещаются в один файл.
use загружает файл и вызывает метод import
в этом пакете. Это действительно только случайно, что его аргумент выглядит как имя модуля. Он ищет файл. Если файл не существует, то он barfs.
Вы можете сделать это, где 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;
По соглашению мы помещаем один пакет в один файл и называем его одним и тем же, но это просто для удобства. Вы можете поместить несколько пакетов в один файл. Поскольку они уже загружены, вам не нужно использовать use
.
Вам также не нужно создавать специальные области для пакетов, поскольку ключевое слово пакета позаботится об этом. Использование фигурных скобок помогает с определением переменных our
. Таким образом, вам не нужны эти блоки, но это хорошая идея.
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