我有以下脚本:
use Modern::Perl;
use List::Compare;
use Set::IntSpan;
use List::Util qw/first/;
use List::MoreUtils qw/firstidx onlyidx/;
use Data::Dumper;
sub get_index_by_data {
my ( $data, $arr ) = @_;
return onlyidx { $_ eq $data } @$arr;
}
sub detect_busy_intervals {
my %params = @_;
$params{epoch_key} = 'epoch' if ( !defined $params{epoch_key} ) ;
my @all_epochs = @ { $params{all_epochs} };
my @free_epochs = map { $_->{ $params{epoch_key} } } @{ $params{data} };
my $lc = List::Compare->new( $params{all_epochs}, \@free_epochs );
my @busy_epochs = $lc->get_Lonly;
@all_epochs = sort { $a <=> $b } @all_epochs;
@free_epochs = sort { $a <=> $b } @free_epochs;
@busy_epochs = sort { $a <=> $b } @busy_epochs;
my @busy_indexes_list = map { get_index_by_data( $_, \@all_epochs) } @busy_epochs;
my $int_span = Set::IntSpan->new(join ",", @busy_indexes_list);
my @spans = spans $int_span;
my @res = ();
for my $i ( @spans ) {
my $busy_start_idx = $i->[0];
my $busy_finish_idx = $i->[1];
my $busy_start_time = $all_epochs[ $busy_start_idx ];
my $busy_finish_time = $all_epochs[ $busy_finish_idx ];
my $prev_free_time_idx = $busy_start_idx - 1;
my $next_free_time_idx = $busy_finish_idx + 1;
my $route = {};
$route->{start} = first { $_->{ $params{epoch_key} } == $all_epochs[$prev_free_time_idx] } @{ $params{data} } ;
$route->{finish} = first { $_->{ $params{epoch_key} } == $all_epochs[$next_free_time_idx] } @{ $params{data} } ;
$route->{start}{epoch} = $params{all_epochs}->[ $busy_start_idx ];
$route->{finish}{epoch} = $params{all_epochs}->[ $busy_finish_idx ];
push @res, $route;
}
return \@res;
}
my @checks_arr = ( 100, 200, 300, 400, 500 );
my $data = [
{ 'epoch' => 100, 'cron_data_id' => 1 },
{ 'epoch' => 500, 'cron_data_id' => 5 },
];
print "Data 1: ".Dumper $data;
my $res = [
{ 'start' => { 'epoch' => 200, 'cron_data_id' => 1 }, 'finish' => { 'epoch' => 400, 'cron_data_id' => 5 } },
];
my $a = detect_busy_intervals( data => $data, all_epochs => \@checks_arr );
print "Result: ".Dumper $a;
print "Data 2: ".Dumper $data;
Run Code Online (Sandbox Code Playgroud)
$data在函数中使用变量后detect_busy_intervals $data更改其值(特别是epoch值不同).但没有任何写入$params{data}内部detect_busy_intervals子!
什么想法可能是错的?
我通过perlcritic检查了代码,也许我做了一些语法错误打印导致变量,但没有检测到问题.
在这些方面:
$route->{start} = first { $_->{ $params{epoch_key} } == $all_epochs[$prev_free_time_idx] } @{ $params{data} } ;
$route->{finish} = first { $_->{ $params{epoch_key} } == $all_epochs[$next_free_time_idx] } @{ $params{data} } ;
Run Code Online (Sandbox Code Playgroud)
您可以将data参数中的hashrefs分配到$route结构中.这些是浅拷贝,因此它们引用data参数引用的相同哈希值.这意味着这些线:
$route->{start}{epoch} = $params{all_epochs}->[ $busy_start_idx ];
$route->{finish}{epoch} = $params{all_epochs}->[ $busy_finish_idx ];
Run Code Online (Sandbox Code Playgroud)
修改原始哈希值.
您可以data通过取消引用hashref(%{})然后创建包含结果列表({})的新哈希引用来从参数分配副本(至少一个副本级别):
my $start = first { $_->{ $params{epoch_key} } == $all_epochs[$prev_free_time_idx] } @{ $params{data} } ;
my $finish = first { $_->{ $params{epoch_key} } == $all_epochs[$next_free_time_idx] } @{ $params{data} } ;
$route->{start} = { %{ $start // {} } };
$route->{finish} = { %{ $finish // {} } };
Run Code Online (Sandbox Code Playgroud)
的// {},即使你的调用,确保first返回民主基金(当它没有找到匹配)的解引用只会导致一个空列表.
如果您的数据结构可能具有进一步的嵌套引用,则一般解决方案将是来自此处列出的模块的深层复制.
use Sereal::Dclone 'dclone';
$route->{start} = dclone first { $_->{ $params{epoch_key} } == $all_epochs[$prev_free_time_idx] } @{ $params{data} } ;
$route->{finish} = dclone first { $_->{ $params{epoch_key} } == $all_epochs[$next_free_time_idx] } @{ $params{data} } ;
Run Code Online (Sandbox Code Playgroud)