Как я могу вызвать пакет Perl, который я определяю в том же файле? - PullRequest
17 голосов
/ 12 апреля 2010

Мне нужно определить несколько модулей и использовать их все в одном файле. Нет, я не могу изменить требование.

Я хотел бы сделать что-то вроде следующего:

{
    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 ...
НАЧАЛО не удалось ...

Как мне заставить это работать?

Ответы [ 3 ]

24 голосов
/ 12 апреля 2010

Бросьте use. Серьезно.

use говорит perl читать код из другого файла, что вам не нужно делать, потому что код находится в том же файле.

14 голосов
/ 12 апреля 2010

Если я не пытаюсь создать личный пакет, о котором никто не должен знать, я помещаю один пакет в файл.Это решает проблему.Но давайте поместим их в один файл.

Использование загружает файл и вызывает метод 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;
10 голосов
/ 12 апреля 2010

По договоренности мы помещаем один пакет в один файл и называем их одинаковыми, но это только для удобства. Вы можете поместить несколько пакетов в один файл. Поскольку они уже загружены, вам не нужно использовать use.

Вам также не нужно создавать специальную область видимости для пакетов, поскольку ключевое слово package заботится об этом. Использование фигурных скобок помогает определить область действия 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...