如何使用与主脚本在同一文件中定义的 Moose class?

How to use a Moose class defined in the same file as the main script?

以下脚本 p.pl 工作正常:

use feature qw(say);
use strict;
use warnings;
use lib '.';
use P1;

my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;

其中 class P1 在文件 P1.pm 中定义:

package P1;
use Moose;

has name => (is => 'rw', isa => 'Str');

1;

但是,当我尝试将 class P1.pm 移动到主脚本中时:

#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;

package P1;
use Moose;

has name => (is => 'rw', isa => 'Str');

我收到错误:

Can't locate object method "name" via package "P1" at ./p.pl line 8.

has 只是一个在 运行 时间执行的常规函数​​调用,因此在您的 say.[=22 之前它不会得到 运行 =]

通常你 use a Moose class, and use Class; is just short for BEGIN { require Class; ... }, so that normally, all the Moose functions like has will have been executed during the compile time of the script that is doing the useing. See also "BEGIN, UNITCHECK, CHECK, INIT and END" in perlmod.

虽然我认为这不是最好的解决方案,但您可以将 package P1; 声明放在 BEGIN { ... } 块中。或者,您可以将 package P1 放在主代码之前(最好放在它自己的块中,因此它有自己的范围)。

但是也有一些反对首先将 class 放在同一个文件中的说法,参见例如In Perl, how do I put multiple class in a single .pm file.

处的答案

您正在尝试在执行对创建它的 has 的调用之前使用该属性。

内联模块比较简单的方法如下:

use feature qw(say);
use strict;
use warnings;

use FindBin qw( $RealBin );
use lib $RealBin;

BEGIN {
   package P1;
   use Moose;

   has name => (is => 'rw', isa => 'Str');

   $INC{"P1.pm"} = 1;
}

use P1;

my $obj = P1->new(name => 'John');
say "The name is: ", $obj->name;

请记住,它仍然不完全相同。例如,该模块现在位于脚本中三个编译指示的范围内。也许你应该使用 App::FatPacker 或类似的代替。