我可以在perl的子例程中声明全局变量吗?

时间:2019-02-21 11:02:29

标签: perl scope global-variables

我可以使用use strict在perl的子例程中声明全局变量吗?

考虑以下代码:

#!/usr/bin/perl
# $Id: foo,v 1.5 2019/02/21 10:41:08 bennett Exp bennett $

use strict;
use warnings;

initialize();

print "$lorem\n";

exit 0;

sub initialize {
    # How would one delcare "$lorem" here such that it is available as
    # a global?

    $lorem = <<_EOM_
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
_EOM_
    ;
}

请注意,我并不是在问(ab)以这种方式使用全局变量是否是个好主意;我敢肯定不是。

我尝试了our$main::的几种组合,但是它们都以您可能期望的方式失败。

在这一点上,我很好奇。能做到吗 我想知道带有BEGIN块的某种恶作剧是否行得通。

以下方法将起作用,但正如@simbabque所指出的那样,这很丑陋:

#!/usr/bin/perl
# $Id: foo,v 1.7 2019/02/21 19:48:26 bennett Exp bennett $

use strict;
use warnings;

initialize();

printf("$main::lorem\n");

exit 0;

sub initialize {
    # How would one delcare "$lorem" here such that is is available as
    # a global-ish?

    our $lorem = <<_EOM_
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
_EOM_
    ;
}

2 个答案:

答案 0 :(得分:5)

对于您的特定示例,您不需要 global 变量。

Perl具有包变量。它们是使用our创建的,也可以使用$namespace::访问的(其中main是默认名称空间,$::也适用于此名称空间)。这些是 global ,但是我们很少这样称呼。

您需要记住,our是一个 lexical 别名,因此,如果在sub内声明它,则该别名将在外部不可用,因为在其中没有lexical别名。更大的范围。

use strict;

sub foo {
    our $bar = 123;
}

foo();
print $bar; # error

您需要在更大的范围内声明变量。

use strict;

our $bar;

sub foo {
    $bar = 123;
}

foo();
print $bar;

这将起作用,因为$bar现在在文件范围内可用。

所有这些仅在use strict打开时适用。如果不声明变量,它将自动成为程序包变量。但是,如果启用strict,则必须声明所有变量。因此,您需要明确。

如果在子程序外部声明my,也可以使用use strict; my $bar; sub foo { $bar = 123; } foo(); print $bar;

my

由于您是在脚本中执行此操作的,并且没有显式的包声明,所以我认为可以确定没有其他模块是安全的。在这种情况下,使用our还是my都没关系。

如果您在包含不同文件的软件包中使用它,将会有所不同。在文件范围内使用package Foo; use strict; my $bar = 123; ### other file use Foo; # no way to get $bar as there is no $Foo::bar 声明的变量属于 private ,因为无法从外部直接访问它们。

our

但是,如果您使用use vars(或过时的package Foo; use strict; our $bar = 123; ### other file use Foo; print $Foo::bar; ),它将变成一个包变量。

our

  

我可以在Perl的子例程中声明全局变量吗?

,您可以使用SELECT t1.chat_channel, Timestampdiff(minute, t1.msgcreated_on, t2.messagecreated_on) FROM (SELECT chat_channel, Min(msgcreated_on) time1 FROM message_tbl WHERE t1.user_type = 'CONSUMER' GROUP BY chat_channel) t1 INNER JOIN (SELECT chat_channel, Min(msgcreated_on) time2 FROM message_tbl WHERE t1.user_type = 'MERHCANT' GROUP BY chat_channel) t2 ON t1.chatchannel = t2.chatchannel 在子例程中声明包变量。但是您不能在声明它们的范围之外将它们作为词法变量进行访问,因此您需要使用其完全限定的程序包名称来访问它们,这很丑陋。

答案 1 :(得分:0)

我相信答案是“否”。 use strict不适用。 use strict的功能之一就是检查变量是否在声明之前使用。

像我上面所做的那样,只想这样做的想法与use strict的编译时检查不一致。

感谢@simbabque帮助我更清晰地进行思考。

我不会删除use strict,而是将巨大的$lorem类型变量(其中有很多)的丑陋性移到一个单独的包中。

-E