UNIVERSAL中的变量/常量?

时间:2011-09-15 10:34:25

标签: perl

我确定我的问题与命名空间和范围有关,但我需要一些帮助!

我正在编写一个带有相当多类的OO Perl脚本,并且要求最小化外部模块的使用(不要问......我知道,我知道......)

所以,我想使用UNIVERSAL提供每个对象都可以使用的日志记录方法。

这是一个非常简单的例子,我刚刚掀起。

use strict;
use warnings;

package House;
sub new {
    my ( $class, %args ) = @_;
    my $self = {
        colour => $args{colour},
        size   => $args{size},
    };
    bless $self, $class;
    return $self;
}

package Boat;
sub new {
    my ( $class, %args ) = @_;
    my $self = {
        doors => $args{doors},
        roof  => $args{roof},
    };
    bless $self, $class;
    return $self;
}

package main;
my $obj = Boat->new( colour => "red", size => "big" );
$obj->_logger("created a big red boat");

my $obj2 = House->new( doors => 1, roof => "yes" );
$obj2->_logger("created a house with a door and roof");

package UNIVERSAL;
use POSIX qw( strftime );
use Sys::Hostname;
my $error_log
    = hostname() . "-" . strftime( "%Y-%m-%d_%H.%M", localtime ) . ".log";

sub _dump {
    my ( $self, $data, $filepath ) = @_;
    open my $fh, ">", $filepath or die "Cannot write to $filepath: $!";
    print $fh $data;
}

sub _logger {
    my ( $self, $data ) = @_;
    my $timestamp = strftime( "%Y-%m-%d %H:%M:%S", localtime );
    $self->_dump( $timestamp . " " . $data, $error_log );
}
__END__

问题是UNIVERSAL命名空间中的$error_log变量似乎不能被其他类中的对象访问,其方式与UNIVERSAL方法相同。

my $error_log的错误:     在./test_uni.pl第47行打开时使用未初始化的值$ filepath。     在串联(。)中使用未初始化的值$ filepath或在./test_uni.pl第47行使用字符串。     无法写入:./test_uni.pl第47行没有此类文件或目录。

实际上,现在我输入这个我想知道在UNIVERSAL中使用类方法的闭包是否有效。

我去尝试的时候,有人对我有任何建议吗?

谢谢!

====================更新======================

UNIVERSAL中带有类方法的闭包似乎有效:

package UNIVERSAL;
use POSIX qw( strftime );
use Sys::Hostname;

{
    sub ERROR_LOG {
    return hostname() . "-" . strftime( "%Y-%m-%d_%H.%M", localtime ) . ".log";
    }
}

然后我使用UNIVERSAL::_loggerUNIVERSAL->ERROR_LOG中调用它。

BUT!我只希望在运行时创建一次ERROR_LOG文件路径。有了这个,它每次都会对它进行评估......

这是唯一的方法吗?如何从其他地方访问UNIVERSAL包中的变量?

谢谢!

1 个答案:

答案 0 :(得分:1)

您的案例中的问题只是在设置UNIVERSAL中的内容之前运行代码。

将主程序包完全向下移动,或将UNIVERSAL包装在BEGIN块中,它可以正常工作。

对于UNIVERSAL或我在这里没有什么奇怪的。


更新:好的,你可以调用_logger(因为已经加载了部分)有点奇怪,但是$ error_log还没有。这是一个演示此行为的最小示例(删除BEGIN块以查看问题):

use strict;
use warnings;

ABC->hey();

package ABC;
BEGIN{
  my $x = 1;
  sub hey(){
    print "x =  $x";
  }
}

也许this解释了它:

  

我既有编译时也有运行时效果。在编译时,编译器会注意到它。这样做的主要用处是安静地使用严格的“变量”,但它对于生成闭包也是必不可少的,详见perlref。但是,实际初始化会延迟到运行时间,因此会在适当的时间执行,例如每次循环执行。

我的阅读是在执行代码之前编译变量声明和子程序,但是在再次到达执行它的行之前不会发生值的赋值(在你的情况下是在你之后)调用子程序,这些子程序是仍然未初始化的值周围的闭包。)