perl 将排序函数移动到包时未初始化值

pn9klfpd  于 2022-11-15  发布在  Perl
关注(0)|答案(2)|浏览(169)

假设我有一个文件main.pl和一个包package.pm
在www.example.com中main.pl我得到了函数

sub GetTimestampFromDateStr {
        my $date_str = shift;

        $logger->debug("[GetTimestampFromDateStr]:(Checking date \"$date_str\"\n"); # Here

        my $unix_timestamp;
        if ( $date_str =~ /^\d{8}\.\d{6}$/ ) { # Here
            $unix_timestamp =
            Time::Piece->strptime( $date_str, '%Y%m%d.%H%M%S' )->epoch();
        }
        else {
            $logger->error( # Here
              "[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
当函数和函数调用都在同一个文件中时,一切都很正常。当将函数原样移动到www.example.com时package.pm,它突然引发了一系列未初始化值的错误。
使用Perl 5.16.3.

qyyhg6bp

qyyhg6bp1#

$a$b是包变量,因此无法跨包边界轻松访问。演示:

use v5.12;

package Foo {
    sub bar {
        say "[$a]";
        say "[$b]";
        1;
    }
}

package main {
    my @x = sort { Foo::bar() } 1 .. 2;
}

您可以通过完全引用变量来解决此问题:

use v5.12;

package Foo {
    sub bar {
        say "[$main::a]";
        say "[$main::b]";
        1;
    }
}

package main {
    my @x = sort { Foo::bar() } 1 .. 2;
}

然而,这将一个假设硬编码到Foo::bar()中--它现在假设总是从main调用它。
多亏了caller,您可以消除硬编码,尽管它有点难看:

use v5.12;

package Foo {
    sub bar {
        no strict 'refs';
        my ( $x, $y ) = map ${ caller . '::' . $_ }, qw( a b );
        say "[$x]";
        say "[$y]";
        1;
    }
}

package main {
    my @x = sort { Foo::bar() } 1 .. 2;
}

更好的解决方案是将$a$b作为函数参数传递。

use v5.12;

package Foo {
    sub bar {
        my ( $x, $y ) = @_;
        say "[$x]";
        say "[$y]";
        1;
    }
}

package main {
    my @x = sort { Foo::bar( $a, $b ) } 1 .. 2;
}
7fhtutme

7fhtutme2#

在只有 n 个日期的情况下,调用GetTimestampFromDateStr2n* log 2(n)* 次的代价有点高,这意味着16个日期会导致128次日期转换,这是一种巨大的浪费。
我建议使用Sort::Key来解决这个问题。
您正在执行lc($TYPE) eq "desc"检查 2n* log 2(n)* 次,而它只需要执行一次。
我建议将检查从比较函数中移出以解决此问题。

use Sort::Key qw( ikeysort rikeysort );

my $sorter =
   ( lc($TYPE) eq "desc"
   ? sub { rikeysort { GetTimestampFromDateStr( $_ ) } @_ }
   : sub { ikeysort  { GetTimestampFromDateStr( $_ ) } @_ }
   );

my @sorted = $sorter->( @unsorted );

也就是说,没有理由转换日期在所有给定的格式,他们使用!

my $sorter =
   ( lc($TYPE) eq "desc"
   ? sub { sort { $b cmp $a } @_ }
   : sub { sort { $a cmp $b } @_ }
   );

my @sorted = $sorter->( @unsorted );

相关问题