免费注册 查看新帖 |

Chinaunix

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

求教高手——关于子程序引用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-11-02 18:24 |只看该作者 |倒序浏览
求教各位高手,在《Intermediate Perl》第七章中关于子程序引用有一段代码,大致如下:


use File::Find;
sub create_find_callback_that_sums_the_size{
    my $total_size = 0;
    return sub{
      if(@_){return $total_size;}
      else{$total_size += -s if -f;}
    };
}
my $callback = create_find_callback_that_sums_the_size();
find($callback, '.');
my $total_size = $callback->('dummy');
print $total_size,"\n";

根据我的理解,create_find_callback_that_sums_the_size子程序的返回值是一个匿名子程序,当该子程序没有参数时,则计算$total_size的值;而当子程序有参数时,则返回$total_size的值。
但是不明白书里面的解释,为什么"If we stick the definition of $total_size into the subroutine that returns the callback reference,we won't have acces to the variable."——“如果我们把$total_size的定义放在返回回调引用的子程序里的话,我们将无法访问这个变量。”?而且,为什么需要用一个没有任何意义的参数dummy去调用返回的匿名子程序才能获得最终的$total_size,而不是在匿名子程序中直接返回$total_size?这段代码应该怎样理解?

小弟初学perl,被这个问题困扰了很久,恳请各位老师不吝赐教,谢谢!

论坛徽章:
0
2 [报告]
发表于 2011-11-02 18:43 |只看该作者
本帖最后由 vinian 于 2011-11-02 18:52 编辑

my 和 sub 的作用域不一样, sub 是文件作用域,my 是 lexical,跳出 lexical, my 定义的变量就不能访问了

  1. $callback->('dummy');
复制代码
是为了执行
  1. if (@_) { return $total_size }
复制代码
dummy 可以用任何代替,但不能为
  1. $callback->();
复制代码
这样会执行 else

参考
  1.   perldoc perlfaq7
复制代码
What's a closure?  和     How do I create a static variable?

论坛徽章:
0
3 [报告]
发表于 2011-11-02 18:59 |只看该作者
回复 2# vinian


    您好,这段代码的字面意思我可以看懂,但不懂内部具体是怎样实现的,烦请您能进一步的讲解一下吗,非常感谢!

论坛徽章:
0
4 [报告]
发表于 2011-11-02 20:47 |只看该作者
Perl的垃圾回收机制,只要有指向这个变量的引用,就不会删除。
包含在一个引用中的匿名子程序,只能通过这个引用来访问,没有别的入口。
闭包就代表一个只能通过引用访问的代码块,不但可以包含子程序,还能包含数据。
可以动态生成子程序。函数定义更加灵活。

论坛徽章:
0
5 [报告]
发表于 2011-11-03 11:53 |只看该作者
回复 4# Perlvim


    return 后面的匿名子程序本身就是一个closure,因为它引用了在其作用域之外的私有变量$total_size,这样理解对吗?
如果这样,那么为什么不能在直接在匿名子程序中计算并返回$total_size的值,而是要用if结构判断有无参数再得到结果呢?

论坛徽章:
0
6 [报告]
发表于 2011-11-03 13:12 |只看该作者
去看File::Find源代码

论坛徽章:
0
7 [报告]
发表于 2011-11-03 13:19 |只看该作者
回复 6# 斯文牛氓


    小弟实在不理解,或许是对perl的了解只是停留在单个点上,请高手把这段代码的实际运行过程讲解一下好吗,包括需要特殊注意的地方?

论坛徽章:
0
8 [报告]
发表于 2011-11-03 14:27 |只看该作者
--这个 File::Find 不怪你,的确难理解--用几次,你慢慢地会有体会的~

1. 为什么"If we stick the definition of $total_size into the subroutine that returns the callback reference,we won't have acces to the variable."

sub create_find_callback_that_sums_the_size{
## my $total_size = 0;
    return sub{
##让你说放在哪合适...这儿
$total_size = 0;   # 放这儿,你怎么用它;
                          # 等你用到它时,它 out of scope 了
      if(@_){return $total_size;}
      else{$total_size += -s if -f;}
    };
}

2. 为什么需要用一个没有任何意义的参数dummy去调用返回的匿名子程序才能获得最终的$total_size,而不是在匿名子程序中直接返回$total_size

--一点问题没有,你的理解正确;自己试试呀~~

use File::Find;
sub create_find_callback_that_sums_the_size{
    my $total_size = 0;
    return sub{
# if(@_){return $total_size;}
# else{$total_size += -s if -f;}
        $total_size += -s if -f;
        return $total_size;
    };
}
my $callback = create_find_callback_that_sums_the_size();
find($callback, '.');
# my $total_size = $callback->('dummy');
my $total_size = $callback->();
print $total_size,"\n";

论坛徽章:
0
9 [报告]
发表于 2011-11-03 14:34 |只看该作者
闭包中的子程序是动态子程序,在写的时候,不能确定是否有参数。

就好像面向对象形式的模块方法,在没有被使用前不能确定调用者和调用的参数。

函数定义是在运行的时候动态生成的。

论坛徽章:
0
10 [报告]
发表于 2011-11-03 14:59 |只看该作者
回复 8# Kitaisky


    您好,按照我的理解,应该是这样:


use File::Find;
sub create_find_callback_that_sums_the_size{
    my $total_size = 0;
    return sub{
            $total_size += -s if -f;
    };
}
my $callback = create_find_callback_that_sums_the_size();
find($callback, '.');
print $total_size,"\n";

因为return出来的匿名子程序已经访问了其作用域之外的$total_size变量,所以形成了一个closure。
而这个匿名子程序被return且被保存在$callback变量中,直接把$callback作为find中的\&wanted参数就可以返回结果。
    按这个思路试了一下,代码执行的结果为空。
    始终不明白是什么原因。
    请各位老师指点一下,不胜感激呀。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP