免费注册 查看新帖 |

Chinaunix

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

求教:Perl 的 static 变量 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-06-10 11:30 |只看该作者 |倒序浏览
Perl 没有定义 static 变量的关键字,但能够实现类似的效果。下面这段代码:

        sub test_static
        {
            my $counter = 5;
            sub next_counter {
                $counter+=2;
                return $counter;
            }
            print "counter= $counter\n";
        }
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        my $tmp2 = next_counter();
        print "tmp2= $tmp2\n";
        test_static();
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        test_static();
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        my $tmp1 = next_counter();
        print "tmp1 = $tmp1\n";
        
如果把 sub test_static 去掉,让变量 $counter 和 sub next_counter 放到 bare block 中,达到 static 变量的目的没有问题。
但把 bare block 放到一个 subroutine 之后,结果比较奇怪,下面是运行的结果:
tmp1 = 2
tmp1 = 4
tmp2= 6
counter= 5
tmp1 = 7
tmp1 = 9
counter= 5
tmp1 = 11
tmp1 = 13

前三行是没有执行过 test_static() 输出的,$counter 默认值为 undef,3次加之后成为 6。接下来调用 test_static(),$counter 被初始化为 5,后来第二次调用 test_static(),$counter 没有被初始化为 5,而是保持原来的值 9,这个怎么解释?

看起来有两个 $counter,一个是 test_static() 的局部变量,另一个是由 next_counter() 维护的全局变量。这有什么根据吗?

求大神帮忙,谢谢!



论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
2 [报告]
发表于 2017-06-10 11:41 |只看该作者
回复 1# bighead1982

$ cat perl_state.pl
use strict;
use warnings;
use 5.010;

sub count {
    state $counter = 0;
    $counter++;
    return $counter;
}

say count();
say count();
say count();

$ perl perl_state.pl
1
2
3

论坛徽章:
0
3 [报告]
发表于 2017-06-10 12:10 |只看该作者
回复 2# jason680

谢谢回答!但我并不是想实现 static 变量的功能,而是想搞清楚那个例子中为什么有那样的输出。

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
4 [报告]
发表于 2017-06-10 12:13 |只看该作者
回复 3# bighead1982

加上...

use strict;
use warnings;

论坛徽章:
0
5 [报告]
发表于 2017-06-10 14:20 |只看该作者
回复 4# jason680

加上
    use strict;
    use warnings;
输出一样啊,没有变化。

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
6 [报告]
发表于 2017-06-10 15:22 |只看该作者
这是未定义行为不应该这么用,或者说是 bug。 实际上 next_counter 只绑定 test_static 第一次执行那个 my $counter。

论坛徽章:
0
7 [报告]
发表于 2017-06-10 19:33 |只看该作者
回复 6# zhlong8

对,是不应该这么用,我也是学 perl 看到这个地方,构造了这段代码试一下。

“实际上 next_counter 只绑定 test_static 第一次执行那个 my $counter” 能解释这个现象。
是不是可以这样理解,编译器实际上分配了两个 $counter,第一个是绑定到 next_counter() 的,第二个则是 test_static() 调用时的 lexical。对于绑定到 next_counter() 的,初始化语句 my $counter = 5; 只有在第一次遇到时才会执行,对于那个 lexical,则每次调用都会执行?

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
8 [报告]
发表于 2017-06-10 22:08 |只看该作者
回复 7# bighead1982

没调用 test_static 直接调用 next_counter 的话它需要访问一个根本还不存在的词法变量,这个怎么都讲不通的,只能说目前的实现是我说的这样。目前有这么个警告 5.024

Variable "%s" will not stay shared(W closure) An inner (nested) named subroutine is referencing alexical variable defined in an outer named subroutine.
When the inner subroutine is called, it will see the value ofthe outer subroutine's variable as it was before and during the *first*call to the outer subroutine; in this case, after the first call to theouter subroutine is complete, the inner and outer subroutines will nolonger share a common value for the variable.  In other words, thevariable will no longer be shared.
This problem can usually be solved by making the inner subroutineanonymous, using the [url=]sub[/url] {} syntax.  When inner anonymous subs thatreference variables in outer subroutines are created, theyare automatically rebound to the current values of such variables.

test_static 每次调用都会生成一个 $counter ,但 next_counter 只跟第一次调用共享这个 $counter 变量,test_static 没调用时会先记着,第一次调用 test_static 时会补上,第二次 test_static 就变成个普通的函数了。


sub test_static
{
    my $counter;
    sub next_counter {
        $counter+=2;
        return $counter;
    }
    say $counter;  # 第一次调用时会记得 next_counter 对 $counter 的修改
    $counter = 5;
    print "counter= $counter\n";
}

say next_counter;
say next_counter;
test_static;
say next_counter;

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
9 [报告]
发表于 2017-06-10 22:25 |只看该作者
Perl 语法比较自由有时会出现这些奇怪的问题,其实直接语法错误就行了,可它却选择尽量猜测你想干什么,结果变成我猜你猜我想干什么??? 后来加了 use strict; use warnings; 之后语言严格了许多,才真正值得信任

论坛徽章:
0
10 [报告]
发表于 2017-06-12 12:20 |只看该作者
回复 8# zhlong8

Variable "%s" will not stay shared(W closure) An inner (nested) named subroutine is referencing alexical variable defined in an outer named subroutine.
When the inner subroutine is called, it will see the value ofthe outer subroutine's variable as it was before and during the *first*call to the outer subroutine; in this case, after the first call to theouter subroutine is complete, the inner and outer subroutines will nolonger share a common value for the variable.  In other words, thevariable will no longer be shared.

这段警告说的比较清楚了。第一次调用 outer subroutine test_static() 之前是共享的,一旦调用之后就不再共享了。下面代码
        
sub test_static
{
     my $counter;
     sub next_counter {
         $counter+=2;
         return $counter;
     }
     say "say $counter";  # 第一次调用时会记得 next_counter 对 $counter 的修改
    $counter = 5;
     print "counter= $counter\n";
}
say next_counter;
say next_counter;
test_static;
say next_counter;
test_static;
test_static;


结果是:

2
4
say 4
counter= 5
7
Use of uninitialized value $counter in concatenation (.) or string at test.pl line 36.
say
counter= 5
Use of uninitialized value $counter in concatenation (.) or string at test.pl line 36.
say
counter= 5
后面两次调用 test_static 都给出警告,而第一次没有。说明第一次调用时是存在的,就是共用的那个,后面的调用就不存在了。


感谢 zhlong8


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP