Как я могу назвать пакет 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 перестала работать...

Как я заставляю это работать?

18
задан Bill the Lizard 13 October 2017 в 12:14
поделиться

3 ответа

Бросьте использовать. Серьезно.

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

24
ответ дан 30 November 2019 в 06:35
поделиться

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

Функция 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;
14
ответ дан 30 November 2019 в 06:35
поделиться

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

Вам также не нужно создавать специальную область видимости для пакетов, так как об этом позаботится ключевое слово 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
10
ответ дан 30 November 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: