【问题标题】:Undefined variables in Perl subroutinesPerl 子例程中的未定义变量
【发布时间】:2014-02-18 01:10:39
【问题描述】:

我是 Perl 新手,希望在理解子程序方面得到一些帮助。在子程序中,是不是有些变量总是未定义的?这是因为子程序中的变量是私有的吗?那么如果我想定义之前未定义的变量怎么办,我该怎么做呢?提前致谢。

【问题讨论】:

标签: perl variables subroutine


【解决方案1】:

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;    

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

阅读更多:

【讨论】:

    【解决方案2】:

    在原始的、未缓解的 Perl 中,变量在范围内是全局的。也就是说,它们存在于您的程序中,从您定义它们的位置到脚本的末尾。此外,在 Perl 中,当您将变量与未定义的值一起使用时,它们就会出现。在字符串中,这被视为空字符串。在数字中,它被视为零。

    因此,在子程序中,如果您在主程序中定义了一个变量,那么它也会在您的子程序中定义:

    $foo = "Hello";
    call_sub();
    
    sub call_sub {
        print "$foo\n";
    }
    

    这将打印“Hello”。

    但是,任何人都不应该在这种模式下使用 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 关键字声明变量)。您可以看到这将如何防止错误。

    然而,声明这些类型的变量被称为词法作用域变量。也就是说,它们可以进出存在。如果一个变量在 block 中定义,那么一旦在 block 之外,它将是未定义的。将块视为花括号:

    子程序是一个块

    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 声明后才会定义。
    • 变量的生存和呼吸范围有限。这可能非常有用。不要像在 Pascal 中那样坐在那里用my 在程序开头声明所有变量。声明它们的使用位置,并在不需要时让它们超出范围。
    • 子程序变量不是私有的,因为子程序可以使用已经声明的变量。这是一个坏主意,因为它允许子例程覆盖主程序中变量的值。因此,为了安全起见,请始终使用 my 声明所有子程序变量。
    • 当您忘记定义要尝试使用的变量时,请使用 use warnings; 向您发出警告。

    最后,我撒了谎,但有一个很好的理由。 Perl 中的变量比我介绍的要复杂一点(很多)。你有命名空间的概念,包变量和本地化变量的方法甚至不是本地的。即使是使用 Perl 多年的人也很难理解其后果。

    use strict; 并没有真正强迫你声明变量。它迫使您要么使用用my 声明的词法范围变量,要么对 变量使用完全限定的变量名(或使用our 声明这些变量)。

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

    如需了解更多信息,请查看PerlSub 关于将my 用于私有变量,并查看PerlMod 以获取关于包变量的完整讨论,使用 local,以及(我怎么会忘记!)新引入的 state 变量。

    【讨论】:

      【解决方案3】:

      一般变量是用 my 命令定义的(从技术上讲,还有一些其他变量,例如 our 和 local,但我从不使用它们)。

      定义变量类型:

      my $variable
      

      如果您在子程序中执行此操作,它将生成您需要的变量。在代码中使用 strict 指令通常是个好主意:

      use strict
      

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

      【讨论】:

      • my $variable 没有“定义变量类型”。它声明了一个变量。
      猜你喜欢
      • 2013-08-13
      • 1970-01-01
      • 1970-01-01
      • 2011-10-08
      • 2017-02-25
      • 2015-09-24
      • 2014-09-17
      • 2019-06-23
      • 1970-01-01
      相关资源
      最近更新 更多