如何如果可能将断点设置为特定的闭包?

问题描述

当使用特定闭包的多个实例时,Perl调试器为每个实例列出相同的行号范围,而闭包实际上是不同的。 由于调试器的b命令的参数是行号,我想知道是否可以为特定的闭包设置断点。

考虑以下交互式示例:

  DB<13> sub _s($) { my $s = $_[0]; sub () { $s }; }
  DB<17> $s1 = _s(1)
  DB<18> $s2 = _s(2)
  DB<20> x $s1->()
0  1
  DB<21> x $s2->()
0  2
  DB<22> x $s1
0  CODE(0x55c7e8754958)
   -> &main::__ANON__ in 0
  DB<23> x $s2
0  CODE(0x55c7e8764990)
   -> &main::__ANON__ in 0

因此,代码引用清楚地表明$s1$s2是不同的。 现在可以在调用$s1时设置断点吗?

注意

我的第一个版本尝试使用sub s($) { ... },导致在尝试调用Syntax error ... (Might be a runaway multi-line ;; string starting on line 2)时出现s(1)。 因此,看来您无法真正覆盖s/old/new/;-)

一个注意事项

如果您在类似这样的行上设置断点

my $checker = sub ($) { ... };

在子例程内部(在闭包内部使用闭包),则每次将$checker分配给{strong>但不时,执行都会停止,而在调用闭包时则不会。 我的解决方法是插入这样的换行符(并将断点设置为...行):

my $checker = sub ($) {
    ...
};

解决方法

根据您的问题,解决方案可能是创建一个“装饰”函数,该函数设置一个固定的断点(并将其分配回$ s1)。

DB<1> sub _s($) { my $s = $_[0]; sub () { $s }; }
DB<2> x $s1 = _s(1)
0  CODE(0x55c7dc96b3a8)
   -> &CODE(0x55c7dc96b3a8) in ???
DB<3> x $s1_nob = $s1
0  CODE(0x55c7dc96b3a8)
   -> &main::__ANON__ in 0
DB<4> x $s1 = sub {$DB::single=1; $s1_nob->()}
0  CODE(0x55c7dc9f1260)
   -> &main::__ANON__[(eval 30)[/usr/share/perl/5.26/perl5db.pl:738]:2] in (eval 30)[/usr/share/perl/5.26/perl5db.pl:738]:2-2
DB<6> x $s1->()
main::CODE(0x55c7dc9f1260)((eval 30)[/usr/share/perl/5.26/perl5db.pl:738]:2):
2:        $s1 = sub {$DB::single=1; $s1_nob->()};
DB<<7>> s
0  1
,

根据@Georg Mavridis的回答,我尝试了以下方法:

  DB<1> sub _s($) { my $s = $_[0]; sub () { $s }; }

  DB<24> sub DEBUG($;$) { my ($f,$d) = @_; sub { $DB::single = $d; $f->() } }

  DB<27> x DEBUG(_s(1),1)->()
main::CODE(0x5647d76c16d0)((eval 30)[/usr/lib/perl5/5.26.1/perl5db.pl:738]:2):
2:  sub DEBUG($;$) { my ($f,$d) = @_; sub { $DB::single = $d; $f->() } };
  DB<<28>> n
0  1
  DB<28> x DEBUG(_s(1),0)->()
0  1

丑陋的部分是DEBUG在内部调用了闭包,因此它必须知道闭包的参数。所以我重新定义了它,改组了参数):

  DB<7> sub DEBUG($$;@) { my ($d,$f,@args) = @_; $DB::single = $d; $f->(@args) }

  DB<8> x DEBUG(1,_s(42))
main::DEBUG((eval 12)[/usr/lib/perl5/5.26.1/perl5db.pl:738]:2):
2:  sub DEBUG($$;@) { my ($d,@args) = @_; $DB::single = $d; $f->(@args) };
  DB<<9>> n
0  42
  DB<9> x DEBUG(0,_s(42))
0  42

现在,您使用第一个参数定义单步执行,第二个参数是闭包,随后的参数将传递给闭包。

但这仍然需要在调用闭包时进行代码修改(将$f->($a,$b,$c)替换为DEBUG($d,$a,$c))。还是不漂亮。

,

您(调试器)似乎无法将断点设置为闭包,即使它有一个名称(继续问题中的代码):

  DB<48> *{main::xxx} = _s(33)

  DB<49> x xxx
0  33
  DB<50> *{main::yyy} = _s(44)

  DB<51> x yyy
0  44
  DB<52> b xxx
Subroutine main::xxx not found.
  DB<55> x ref \&xxx
0  'CODE'
  DB<56> sub zzz() { 22 }  ### let's compare with a "regular" subroutine

  DB<57> x zzz
0  22
  DB<58> x ref \&zzz
0  'CODE'

我想Perl需要增强功能。