免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3863 | 回复: 3
打印 上一主题 下一主题

大家对这个程序怎么看?谁能帮忙用 ruby、python 实现一下,看看结果? [复制链接]

论坛徽章:
0
1 [报告]
发表于 2007-09-21 09:24 |显示全部楼层
你的程序中的f里面的$x没有被初始化,所以是0。如下就正常了:
use strict;
use warnings;
BEGIN
{
  my $x = 'A';
  sub f { sub { $x++ }       }
  sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4;


BEGIN块在程序其他部分之前执行,可以保证使用子程序之前就初始化了"静态"变量。

论坛徽章:
0
2 [报告]
发表于 2007-09-21 14:10 |显示全部楼层
这可能是perl的一个小bug,但是也可以看做不是。

普通的sub在运行前只编译一次,而匿名sub的每次调用都会重新编译。后者在作为closure使用的时候,应该在每次调用的时候取所在环境中的变量的值——类似于静态变量。

但从这个程序看来,运行阶段,f中的closure只取了所在sub的“可见”的变量,对于f可见的$x没有保留。也就是说,虽然f可以看见$x,但是由于在f中并没有提到$x,所以里面的closure在运行的时候就成了没有初始化的$x.  这在编译中通过了,不会报错,但是在运行中就出现了未预料的结果。
解决方法1,可以像3楼提到的,在{}前增加BEGIN,确保在加载阶段就正确初始化;
解决方法2,在f中“提及”一下闭包使用的变量,如下代码就可得到预期的结果:

use strict;
use warnings;
{
  my $x = 'A';
  sub f {
         my $y = $x;  #提一下$x,让closure看到。$y is useless。
         sub { $x++ }     
        }
  sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4;


其实,g和f的区别,就是g里面提到了$x,而在f中是隐含看到$x的。

实验验证:
1.不提及变量,结果为未初始化
use strict;
use warnings;
{
  my $x = 'A';   #给 g 所用
  my $y = '5';   #给 f 所用
  sub f {
        sub {  
         print "<",$y++,">";  #第一次运行时,closure看不见$y,只能取0初始化;         
                 $y                             # 返回值为$y+1                     
               }     
        }

  sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4; #打印结果:<0>1A,<1>2B,<2>3C,<3>4D,

2。提及变量,结果正常。
use strict;
use warnings;
{
  my $x = 'A';
        my $y = '5';
  sub f {
             my $z = $y;  #提一下$y,让closure看到。
         sub {  
                 print "<",$y++,">";
                $y
                                 }     
        }
  sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4;  # 打印: <5>6A,<6>7B,<7>8C,<8>9D,

[ 本帖最后由 royalzhang 于 2007-9-21 14:57 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2007-09-21 15:01 |显示全部楼层
原帖由 perljoker 于 2007-9-21 14:39 发表
却能自己记录自己的1,2,3 ...

关键在于初始化。closure在第一次调用以后,就会保留上下文的一个复制,所以纪录自己的1,2,3是正常的。

论坛徽章:
0
4 [报告]
发表于 2007-09-21 15:34 |显示全部楼层
刚找到perlbug上类似的讨论:
http://rt.perl.org/rt3/Public/Bug/Display.html?id=7519
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP