编程时多多思考吧,别光掌握perl的古怪用法而不理解其精髓!
flw
|
21#
flw 发表于 2007-09-18 12:32
下面再来看看 grep:
[Copy to clipboard] [ - ]
CODE:
flw@debian:~/perl-5.9.5$ cat ttt.pl
@b=(70,80,90); #@a = map { $_/10 } @b; @a = grep { $_==80 } @b; #@a = sort sub { $b<=>$a }, @b; flw@debian:~/perl-5.9.5$ ./perl -Dtls ttt.pl (ttt.pl:0) ENTER scope 2 at perly.c:351 (ttt.pl:3) ENTER scope 3 at op.c:7795 (ttt.pl:3) LEAVE scope 3 at op.c:8390 (ttt.pl:4) ENTER scope 3 at op.c:7795 (ttt.pl:3) LEAVE scope 3 at op.c:8390 (ttt.pl:4) LEAVE scope 2 at perly.c:680 (ttt.pl:0) LEAVE scope 1 at perl.c:2304 (ttt.pl:0) ENTER scope 1 at perl.c:2312 (ttt.pl:0) popping jumplevel was bf8ab200, now 82122a0 (ttt.pl:0) Setting up jumplevel bf8ab20c, was 82122a0 EXECUTING... (ttt.pl:0) Entering new RUNOPS level => (ttt.pl:0) enter (ttt.pl:0) ENTER scope 2 at pp_hot.c:1712 Entering block 0, type BLOCK => (ttt.pl:0) nextstate => (ttt.pl:1) pushmark => * (ttt.pl:1) const(IV(70)) => * IV(70) (ttt.pl:1) const(IV(80)) => * IV(70) IV(80) (ttt.pl:1) const(IV(90)) => * IV(70) IV(80) IV(90) (ttt.pl:1) pushmark => * IV(70) IV(80) IV(90) * (ttt.pl:1) gv(main::b) => * IV(70) IV(80) IV(90) * GV() (ttt.pl:1) rv2av => * IV(70) IV(80) IV(90) * AV() (ttt.pl:1) aassign => (ttt.pl:1) nextstate => (ttt.pl:3) pushmark => * (ttt.pl:3) pushmark => ** (ttt.pl:3) gv(main::b) => ** GV() (ttt.pl:3) rv2av => ** IV(70) IV(80) IV(90) (ttt.pl:3) grepstart (ttt.pl:3) ENTER scope 3 at pp_ctl.c:933 (ttt.pl:3) ENTER scope 4 at pp_ctl.c:940 => ** IV(70) ** IV(80) IV(90) (ttt.pl:3) gvsv(main::_) => ** IV(70) ** IV(80) IV(90) IV(70) (ttt.pl:3) const(IV(80)) => ** IV(70) ** IV(80) IV(90) IV(70) IV(80) (ttt.pl:3) eq => ** IV(70) ** IV(80) IV(90) SV_NO (ttt.pl:3) scope => ** IV(70) ** IV(80) IV(90) SV_NO (ttt.pl:3) grepwhile (ttt.pl:3) LEAVE scope 4 at pp_hot.c:2336 (ttt.pl:3) ENTER scope 4 at pp_hot.c:2366 => ** IV(70) * IV(80) * IV(90) (ttt.pl:3) gvsv(main::_) => ** IV(70) * IV(80) * IV(90) IV(80) (ttt.pl:3) const(IV(80)) => ** IV(70) * IV(80) * IV(90) IV(80) IV(80) (ttt.pl:3) eq => ** IV(70) * IV(80) * IV(90) SV_YES (ttt.pl:3) scope => ** IV(70) * IV(80) * IV(90) SV_YES (ttt.pl:3) grepwhile (ttt.pl:3) LEAVE scope 4 at pp_hot.c:2336 (ttt.pl:3) ENTER scope 4 at pp_hot.c:2366 => ** IV(80) IV(80) * IV(90) * (ttt.pl:3) gvsv(main::_) => ** IV(80) IV(80) * IV(90) * IV(90) (ttt.pl:3) const(IV(80)) => ** IV(80) IV(80) * IV(90) * IV(90) IV(80) (ttt.pl:3) eq => ** IV(80) IV(80) * IV(90) * SV_NO (ttt.pl:3) scope => ** IV(80) IV(80) * IV(90) * SV_NO (ttt.pl:3) grepwhile (ttt.pl:3) LEAVE scope 4 at pp_hot.c:2336 (ttt.pl:3) LEAVE scope 3 at pp_hot.c:2343 => * IV(80) (ttt.pl:3) pushmark => * IV(80) * (ttt.pl:3) gv(main::a) => * IV(80) * GV() (ttt.pl:3) rv2av => * IV(80) * AV() (ttt.pl:3) aassign => (ttt.pl:3) leave (ttt.pl:0) POPBLOCK scope 2 at pp_hot.c:1814 Leaving block 0, type BLOCK (ttt.pl:0) LEAVE scope 2 at pp_hot.c:1853 (ttt.pl:0) leaving RUNOPS level (ttt.pl:0) popping jumplevel was bf8ab20c, now 82122a0 (ttt.pl:0) Setting up jumplevel bf8ab200, was 82122a0 (ttt.pl:0) popping jumplevel was bf8ab200, now 82122a0 (ttt.pl:0) LEAVE scope 1 at perl.c:567 flw@debian:~/perl-5.9.5$ 和 map 类似,callback 将最后一句的执行结果,用 SV_YES 和 SV_NO 的形式压入堆栈, grepwhile 将其弹出,然后判断,根据情况,修改 destination list。 grepwhile 的实现比 map/sort 都要简单得多,下面是全部代码:
[Copy to clipboard] [ - ]
CODE:
2329 PP(pp_grepwhile)
2330 { 2331 dVAR; dSP; 2332 2333 if (SvTRUEx(POPs)) 2334 PL_stack_base[PL_markstack_ptr[-1]++] = PL_stack_base[*PL_markstack_ptr]; 2335 ++*PL_markstack_ptr; 2336 LEAVE; /* exit inner scope */ 2337 2338 /* All done yet? */ 2339 if (PL_stack_base + *PL_markstack_ptr > SP) { 2340 I32 items; 2341 const I32 gimme = GIMME_V; 2342 2343 LEAVE; /* exit outer scope */ 2344 (void)POPMARK; /* pop src */ 2345 items = --*PL_markstack_ptr - PL_markstack_ptr[-1]; 2346 (void)POPMARK; /* pop dst */ 2347 SP = PL_stack_base + POPMARK; /* pop original mark */ 2348 if (gimme == G_SCALAR) { 2349 if (PL_op->op_private & OPpGREP_LEX) { 2350 SV* const sv = sv_newmortal(); 2351 sv_setiv(sv, items); 2352 PUSHs(sv); 2353 } 2354 else { 2355 dTARGET; 2356 XPUSHi(items); 2357 } 2358 } 2359 else if (gimme == G_ARRAY) 2360 SP += items; 2361 RETURN; 2362 } 2363 else { 2364 SV *src; 2365 2366 ENTER; /* enter inner scope */ 2367 SAVEVPTR(PL_curpm); 2368 2369 src = PL_stack_base[*PL_markstack_ptr]; 2370 SvTEMP_off(src); 2371 if (PL_op->op_private & OPpGREP_LEX) 2372 PAD_SVl(PL_op->op_targ) = src; 2373 else 2374 DEFSV = src; 2375 2376 RETURNOP(cLOGOP->op_other); 2377 } 2378 } grep 的 callback 除了将结果压入堆栈之外,没有修改任何其它数据,更不用说受上一次调用的影响了, 因此不能算 closure。 |