Perl子例程中的未定义变量

时间:2014-02-18 01:10:40

标签: perl variables subroutine

我是Perl的新手,希望在理解子程序方面有所帮助。在子程序中,某些变量是否总是未定义?这是因为子程序中的变量是私有的吗?那么,如果我想要定义所述先前未定义的变量,我将如何去做呢?提前致谢。

3 个答案:

答案 0 :(得分:4)

Perl中的变量不是私有的,但它们的范围有限。例如在子例程中用my声明它们时。子例程的参数存储在变量@_

do_stuff($foo, $bar);

sub do_stuff {
    my ($first, $second) = @_;   # direct assignment
    print "First: $first, Second: $second\n";
}

my声明使变量在词法上限定为周围的块{ ... },这意味着它们受到保护,并且当执行离开块时它们超出范围。

也可以使用数组函数shiftpop访问子例程的参数,这在Perl代码中很常见:

sub do_stuff {
    my $first   = shift;
    my $second) = shift;    

除了它还从@_数组中删除了元素外,它也做了同样的事情。

了解更多:

答案 1 :(得分:2)

在原始的,未减轻的Perl中,变量在范围内是 global 。也就是说,它们存在于您的程序中,从您定义它们到脚本的末尾。此外,在Perl中,当您使用未定义的值时,变量会存在。在字符串中,这被视为空字符串。在数字中,它被视为零。

因此,在子程序中,如果在主程序中定义了一个变量,它就在子程序中定义:

$foo = "Hello";
call_sub();

sub call_sub {
    print "$foo\n";
}

那将打印“你好”。

但是,没有人应该在这种模式下使用Perl,因为它很容易出错:

$name = "Bob"
print "Hello $Name!\n";

糟糕!我在定义它时使用了$name,在使用它时使用了$Name。另外,您不需要这样的全局变量。否则,子例程可能会覆盖主程序变量。使编写大型复杂程序变得非常非常困难。

为了解决这个问题,我们强烈建议您将这两行放在代码中:

use strict;
use warnings;

use warnings;会发出各种各样的警告,例如未初始化的变量被视为字符串和数字。

use strict;会带来更大的变化。简单地说(并且不正确),use strict会强制您声明您的变量,然后才能使用它们。

use warnings;
use strict;

my $name = "Bob"
print "Hello $Name\n";

此程序无效,因为$Name从未声明(您使用my关键字声明变量)。您可以看到这将如何防止错误。

但是,声明这些类型的变量称为词法范围变量。也就是说,它们可以进出存在。如果在中定义了变量,则在之外将不定义该变量。可以将块视为花括号:

子程序是一个块

sub foo {  # Curly brace starts the block
   ...
}          # Curly brace ends the block

这意味着如果你在子程序中定义一个变量,它只在那个子程序中。

此外,whilefor循环是块:

for my $foo ( @foo_list ) {   # The variable $foo is only defined in this loop
   ...
}                             # End of block and end of loop

while ( my $foo = <@foo_list> ) {   # Again, $foo is only in this block
   ...
}                                   # End of the block

if ( $foo == $bar )   {        # Another block
   my $foo = 1;                # $foo is defined in the block
}                              # $foo is no longer defined

你甚至可以使用花括号:

my $foo = 1;
print "$foo\n"                # Prints 1
{
    my $foo = 2;              # Redefines $foo it's a different $foo!
    print "$foo\n"            # Prints 2
}                             # End of block, $foo in block is now out of scope
print "$foo\n";               # Prints 1 because the original $foo is in scope.

让我们来看看:

my $foo = 2;
my $bar = 5;
print "$foo\n";              # Prints 2
call_sub(5);                 # Prints "Foo is 5!"
print $foo\n";               # Prints 2

sub call_sub {
    my $foo = shift;         # Different $foo from main program!
    print "Foo is $foo!\n";
    print "Bar is $bar\n";   # Will print "Bar is 5" because $bar is in scope
}                            # Subroutine's $foo falls out of scope

正如您所看到的,$bar是在我调用子例程之前定义的,因此它在子例程中定义并且仍在范围内。但是,我的子例程中的$foo被重新声明,并一直保留到子例程结束并超出范围。因此,我的子程序使用$foo不会干扰我的主程序。

所以,回答你的问题:

  • 始终使用use strict;。这将迫使您在变量可以使用之前声明它们。
  • 在使用my声明变量之前,不会定义变量。
  • 变量的生活和呼吸范围有限。这非常有用。不要坐在那里,用my在程序开头声明所有变量,就像在Pascal中一样。在使用它们的地方声明它们,并在它们不需要时让它们超出范围。
  • 子程序变量不是私有,因为子程序可以使用已经声明的变量。这是一个坏主意,因为它允许子程序覆盖主程序中变量的值。因此,始终使用my声明所有子例程变量是安全的。
  • 当您忘记定义您尝试使用的变量时,请使用use warnings;发出警告。

最后,我撒了谎,但这是有充分理由的。 Perl中的变量比我提出的要复杂得多(很多)。您有名称空间的概念,包变量以及本地化变量的方法甚至不是本地的。即使与Perl合作多年的人也很难理解其后果。

use strict;并没有真正强迫你声明变量。它会强制您使用通过my声明的词法范围变量,或使用变量的完全限定变量名(或使用our宣布那些)。

但是,最后,use strict;在某种程度上会强制您声明变量,因为您将在Perl中使用的99%变量将使用my声明。当您了解有关Perl的更多信息时,您可以了解更多关于其他1%的内容。

有关详细信息,请查看PerlSub关于使用my获取私有变量的信息,并查看PerlMod以获取有关的完整讨论包变量,使用 local ,以及(我怎么能忘记!)新引入的 state 变量。

答案 2 :(得分:1)

一般情况下,变量是用my命令定义的(从技术上来说,还有一些其他的变量,比如我们和本地,但我从不使用它们。)

定义变量类型:

my $variable

如果你在子程序中这样做,它将生成你需要的变量。在代码中使用strict指令通常是个好主意:

use strict

当你忘记定义事情时,这会给你一些警告。