将Perl排序相关函数移至包后出现未初始化值错误求助
Perl 函数移至模块后出现未初始化值错误问题
我有main.pl和package.pm两个文件。原本在main.pl中定义了如下函数:
sub GetTimestampFromDateStr { my $date_str = shift; $logger->debug("[GetTimestampFromDateStr]:(Checking date \"$date_str\"\n"); # 此处 my $unix_timestamp; if ( $date_str =~ /^\d{8}\.\d{6}$/ ) { # 此处 $unix_timestamp = Time::Piece->strptime( $date_str, '%Y%m%d.%H%M%S' )->epoch(); } else { $logger->error( # 此处 "[GetTimestampFromDateStr]:(Invalid date format for \"$date_str\", must be \"%Y%m%d.%H%M%S\" i.e. \"20170125.123500\"\n" ); } return $unix_timestamp; }
该函数被以下函数调用:
sub DATESORT { my $TYPE = shift; my $ts_a = GetTimestampFromDateStr($a); my $ts_b = GetTimestampFromDateStr($b); if ( lc($TYPE) eq "desc" ) { $ts_b <=> $ts_a; } else { $ts_a <=> $ts_b; } }
并通过sort { DATESORT('ASC') } @tran_dates_to_load作为排序函数调用。当这些函数和调用逻辑在同一文件时一切正常,但将函数原样移至package.pm后,突然出现大量未初始化值错误。使用的Perl版本为5.16.3。
问题根源
$a/$b的作用域冲突:Perl里sort块的$a和$b是当前包的全局变量。把DATESORT移到模块后,函数会默认在自身包的命名空间找这两个变量,而非调用sort的main包中的变量,导致传入GetTimestampFromDateStr的是未初始化值,触发连锁错误。$logger的作用域问题:如果$logger是在main.pl中定义的,模块默认无法访问主包的这个变量,会导致$logger未初始化,同样抛出错误。
解决方法
修复$a/$b的问题
方案1:显式引用主包的$a和$b
直接在模块的DATESORT里指定使用main包的变量:
sub DATESORT { my $TYPE = shift; my $ts_a = GetTimestampFromDateStr($main::a); my $ts_b = GetTimestampFromDateStr($main::b); if ( lc($TYPE) eq "desc" ) { $ts_b <=> $ts_a; } else { $ts_a <=> $ts_b; } }
方案2:将$a/$b作为参数传入(更规范)
调整sort调用方式和DATESORT函数,避免依赖全局变量:
# main.pl中的sort调用 sort { DATESORT('ASC', $a, $b) } @tran_dates_to_load # package.pm中的DATESORT函数 sub DATESORT { my ($TYPE, $a_val, $b_val) = @_; my $ts_a = GetTimestampFromDateStr($a_val); my $ts_b = GetTimestampFromDateStr($b_val); if ( lc($TYPE) eq "desc" ) { $ts_b <=> $ts_a; } else { $ts_a <=> $ts_b; } }
修复$logger的问题
- 如果
$logger是全局变量,在模块中显式引用$main::logger即可; - 更规范的做法是将
$logger作为参数传入函数:
# package.pm中的GetTimestampFromDateStr sub GetTimestampFromDateStr { my ($date_str, $logger) = @_; $logger->debug("[GetTimestampFromDateStr]:(Checking date \"$date_str\"\n"); my $unix_timestamp; if ( $date_str =~ /^\d{8}\.\d{6}$/ ) { $unix_timestamp = Time::Piece->strptime( $date_str, '%Y%m%d.%H%M%S' )->epoch(); } else { $logger->error( "[GetTimestampFromDateStr]:(Invalid date format for \"$date_str\", must be \"%Y%m%d.%H%M%S\" i.e. \"20170125.123500\"\n" ); } return $unix_timestamp; } # 调用时传入logger my $ts_a = GetTimestampFromDateStr($a_val, $logger);
内容的提问来源于stack exchange,提问作者noah
相关产品推荐
相关产品推荐

