【问题标题】:What is the difference between 'my' and 'our' in Perl?Perl 中的“我的”和“我们的”有什么区别?
【发布时间】:2010-10-25 02:36:54
【问题描述】:

我知道 Perl 中的 my 是什么。它定义了一个仅存在于定义它的块范围内的变量。 our 是做什么的?

ourmy 有何不同?

【问题讨论】:

    标签: perl scope


    【解决方案1】:

    ourmy 有何不同,our 有何不同 做吗?

    总结:

    自 Perl 5 起可用,my 是一种声明非包变量的方法,即:

    • 私人
    • 非全局
    • 与任何包分开,使变量不能$package_name::variable的形式访问。

    另一方面,our 变量是包变量,因此自动:

    • 全局变量
    • 绝对不是私人的
    • 不一定是新的
    • 可以在包外(或词法范围)使用 限定命名空间,如$package_name::variable

    使用 our 声明变量允许您预先声明变量以便在 use strict 下使用它们而无需获取错字警告或编译时错误。从 Perl 5.6 开始,它取代了过时的 use vars,它只是文件范围,而不是像 our 那样的词法范围.

    例如,package main 中变量 $x 的正式限定名称是 $main::x。声明 our $x 允许您在声明范围内使用裸 $x 变量而不会受到惩罚(即,不会导致错误),当脚本使用use strictuse strict "vars"。范围可能是一个、两个或多个包,或者一个小块。

    【讨论】:

    • 那么我们与本地有何不同?
    • @Nathan Fellman, local 不创建变量。它根本与myour 无关。 local临时备份变量的值并清除其当前值。
    • our 变量不是包变量。它们不是全局范围的,而是词法范围的变量,就像my 变量一样。您可以在以下程序中看到这一点:package Foo; our $x = 123; package Bar; say $x;。如果你想“声明”一个包变量,你需要使用use vars qw( $x );our $x; 声明了一个词法范围变量,该变量别名为编译 our 的包中的同名变量。
    【解决方案2】:

    我曾经在 Perl 中遇到过一些关于词法声明的陷阱让我很困惑,这些陷阱也与这个问题有关,所以我只是在这里添加我的总结:

    1.定义还是声明?

    local $var = 42;
    print "var: $var\n";
    

    输出为var: 42。但是我们无法判断local $var = 42; 是定义还是声明。但是这个怎么样:

    use strict;
    use warnings;
    
    local $var = 42;
    print "var: $var\n";
    

    第二个程序会报错:

    Global symbol "$var" requires explicit package name.
    

    $var 没有定义,这意味着local $var; 只是一个声明!在使用local声明变量之前,请确保之前已将其定义为全局变量。

    但为什么这不会失败?

    use strict;
    use warnings;
    
    local $a = 42;
    print "var: $a\n";
    

    输出为:var: 42

    这是因为$a$b 是Perl 中预定义的全局变量。还记得sort 函数吗?

    2。词法还是全局?

    在开始使用 Perl 之前我是一名 C 程序员,所以词法变量和全局变量的概念对我来说似乎很简单:它只对应于 C 中的自动变量和外部变量。但有一些小的区别:

    在 C 中,外部变量是在任何功能块之外定义的变量。另一方面,自动变量是在功能块内定义的变量。像这样:

    int global;
    
    int main(void) {
        int local;
    }
    

    在 Perl 中,事情很微妙:

    sub main {
        $var = 42;
    }
    
    &main;
    
    print "var: $var\n";
    

    输出为var: 42$var 是一个全局变量,即使它是在功能块中定义的!实际上在 Perl 中,任何变量都默认声明为全局变量。

    教训是始终在 Perl 程序的开头添加use strict; use warnings;,这将迫使程序员显式声明词法变量,这样我们就不会被一些理所当然的错误搞砸。

    【讨论】:

    【解决方案3】:

    my 用于局部变量,而our 用于全局变量。

    更多阅读请访问 Variable Scoping in Perl: the basics

    【讨论】:

    • 小心折腾本地和全球这两个词。正确的术语是词汇和包装。您不能在 Perl 中创建真正的全局变量,但有些已经存在,例如 $_,并且 local 指的是具有本地化值的包变量(由 local 创建),而不是词法变量(由 my 创建)。
    • ${^Potato} 是全球性的。无论你在哪里使用它,它都引用同一个变量。
    【解决方案4】:

    一个例子:

    use strict;
    
    for (1 .. 2){
        # Both variables are lexically scoped to the block.
        our ($o);  # Belongs to 'main' package.
        my  ($m);  # Does not belong to a package.
    
        # The variables differ with respect to newness.
        $o ++;
        $m ++;
        print __PACKAGE__, " >> o=$o m=$m\n";  # $m is always 1.
    
        # The package has changed, but we still have direct,
        # unqualified access to both variables, because the
        # lexical scope has not changed.
        package Fubb;
        print __PACKAGE__, " >> o=$o m=$m\n";
    }
    
    # The our() and my() variables differ with respect to privacy.
    # We can still access the variable declared with our(), provided
    # that we fully qualify its name, but the variable declared
    # with my() is unavailable.
    print __PACKAGE__, " >> main::o=$main::o\n";  # 2
    print __PACKAGE__, " >> main::m=$main::m\n";  # Undefined.
    
    # Attempts to access the variables directly won't compile.
    # print __PACKAGE__, " >> o=$o\n";
    # print __PACKAGE__, " >> m=$m\n";
    
    # Variables declared with use vars() are like those declared
    # with our(): belong to a package; not private; and not new.
    # However, their scoping is package-based rather than lexical.
    for (1 .. 9){
        use vars qw($uv);
        $uv ++;
    }
    
    # Even though we are outside the lexical scope where the
    # use vars() variable was declared, we have direct access
    # because the package has not changed.
    print __PACKAGE__, " >> uv=$uv\n";
    
    # And we can access it from another package.
    package Bubb;
    print __PACKAGE__, " >> main::uv=$main::uv\n";
    

    【讨论】:

      【解决方案5】:

      让我们想想解释器实际上是什么:它是一段代码,将值存储在内存中,并让它解释的程序中的指令通过它们的名称访问这些值,这些名称在这些指令中指定。因此,解释器的主要工作是制定规则,说明我们应该如何使用这些指令中的名称来访问解释器存储的值。

      在遇到“my”时,解释器创建一个词法变量:一个命名值,解释器只能在执行块时访问,并且只能从该句法块中访问。在遇到“我们的”时,解释器为包变量创建一个词法别名:它将一个名称绑定到包的值上,从那时起解释器应该将其作为词法变量的名称进行处理,直到块完成同名变量。

      效果是你可以假装你正在使用一个词法变量,并绕过对包变量的完全限定的“使用严格”规则。由于解释器在第一次使用时会自动创建包变量,因此使用“我们的”的副作用也可能是解释器也会创建一个包变量。在这种情况下,创建了两件事:一个包变量,解释器可以从任何地方访问它,只要它按照“use strict”的要求正确指定(前面加上其包的名称和两个冒号),和 它的词法别名。

      来源:

      【讨论】:

        【解决方案6】:

        尝试使用以下程序:

        #!/usr/local/bin/perl
        use feature ':5.10';
        #use warnings;
        package a;
        {
        my $b = 100;
        our $a = 10;
        
        
        print "$a \n";
        print "$b \n";
        }
        
        package b;
        
        #my $b = 200;
        #our $a = 20 ;
        
        print "in package b value of  my b $a::b \n";
        print "in package b value of our a  $a::a \n";
        

        【讨论】:

        • 这解释了 my 和 our 的区别。 my 变量超出了花括号外的范围并被垃圾回收,但 our 变量仍然存在。
        【解决方案7】:
        print "package is: " . __PACKAGE__ . "\n";
        our $test = 1;
        print "trying to print global var from main package: $test\n";
        
        package Changed;
        
        {
                my $test = 10;
                my $test1 = 11;
                print "trying to print local vars from a closed block: $test, $test1\n";
        }
        
        &Check_global;
        
        sub Check_global {
                print "trying to print global var from a function: $test\n";
        }
        print "package is: " . __PACKAGE__ . "\n";
        print "trying to print global var outside the func and from \"Changed\" package:     $test\n";
        print "trying to print local var outside the block $test1\n";
        

        会输出这个:

        package is: main
        trying to print global var from main package: 1
        trying to print local vars from a closed block: 10, 11
        trying to print global var from a function: 1
        package is: Changed
        trying to print global var outside the func and from "Changed" package: 1
        trying to print local var outside the block 
        

        如果在尝试运行脚本时使用“use strict”会失败:

        Global symbol "$test1" requires explicit package name at ./check_global.pl line 24.
        Execution of ./check_global.pl aborted due to compilation errors.
        

        【讨论】:

        • 请提供某种解释。像这样转储代码很少被认为是合适的。
        • 简而言之:我们的(如名称 sais)是一个变量声明,可以从脚本中的任何位置(函数、块等)使用该变量,默认情况下每个变量(以防万一)未声明)属于“主”包,即使在脚本中删除另一个包后,我们的变量仍然可以使用。如果在块或函数中声明,“我的”变量只能在该块/函数中使用。如果“我的”变量被声明为未在块中关闭,它可以在 scriot 中的任何位置使用,也可以在关闭的块中或在函数中作为“我们的”变量使用,但不能在包更改的情况下使用
        • 我上面的脚本显示默认情况下我们在“main”包中,然后脚本从“main”包中打印一个“我们的”变量(不是在一个块中关闭),然后我们声明两个函数中的“我的”变量并从该函数中打印它们。然后我们从另一个函数打印一个“我们的”变量以显示它可以在函数中使用。然后我们将包更改为“已更改”(不再是“主”),我们再次成功打印“我们的”变量。然后尝试在函数外部打印“我的”变量并失败。该脚本仅显示“我们的”和“我的”用法之间的区别。
        【解决方案8】:

        来自 Cartman 和 Olafur 的 PerlMonks 和 PerlDoc 链接是一个很好的参考 - 以下是我的总结:

        my 变量在{} 定义的单个块内的词法范围内,如果不在{}s 内,则在同一文件内。它们不能从定义在同一词法范围/块之外的包/子例程中访问。

        our 变量在包/文件中的范围内,并且可以从userequire 的任何代码访问,该包/文件 - 通过预先添加适当的命名空间来解决包之间的名称冲突。

        为了完善它,local 变量是“动态”作用域的,与 my 变量的不同之处在于它们也可以从同一块内调用的子例程中访问。

        【讨论】:

        • +1 表示“my 变量在同一文件中的词法范围 [...] 如果不在 {}s 中”。这对我很有用,谢谢。
        【解决方案9】:
        #!/usr/bin/perl -l
        
        use strict;
        
        # if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
        #my $lol = 'eeeeeeeeeee' ;
        # no errors or warnings at any case, despite of 'strict'
        
        our $lol = eval {$lol} || 'lol' ;
        
        print $lol;
        

        【讨论】:

        • 你能解释一下这段代码的意思吗?为什么ourmy 不同?这个例子是如何显示的?
        【解决方案10】:

        这只是与问题有点相关,但我刚刚发现了一个(对我而言)晦涩难懂的 perl 语法,您可以将其与“我们的”(包)变量一起使用,而您不能将其与“我的”一起使用(局部)变量。

        #!/usr/bin/perl
        
        our $foo = "BAR";
        
        print $foo . "\n";
        ${"foo"} = "BAZ";
        print $foo . "\n";
        

        输出:

        BAR
        BAZ
        

        如果您将“我们的”更改为“我的”,这将不起作用。

        【讨论】:

        • 不是这样。 $foo ${foo} ${'foo'} ${"foo"} 对于变量赋值或取消引用都是一样的。将上面示例中的 our 替换为 my 确实有效。您可能经历过尝试取消引用 $foo 作为包变量,例如 $main::foo 或 $::foo 仅适用于包全局变量,例如使用 our 定义的那些。
        • 刚刚使用 v5.20 重新测试,它肯定不会提供与我相同的输出(它会打印两次 BAR。)
        • 我的测试(在 Windows 上):perl -e "my $foo = 'bar'; print $foo; ${foo} = 'baz'; pr int $foo" 输出:barbazperl -e "my $foo = 'bar'; print $foo; ${"foo"} = 'baz'; print $foo" 输出:barbazperl -e "my $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo" 输出:barbar 所以在我的测试中,我陷入了同样的境地陷阱。 ${foo} 与 $foo 相同,括号在插值时很有用。 ${"foo"} 实际上是对主要符号表 $main::{} 的查找,因此只包含包作用域变量。
        • ${"main::foo"}、${"::foo"} 和 $main::foo 与 ${"foo"} 相同。速记是包敏感的perl -e "package test; our $foo = 'bar'; print $foo; ${\"foo\"} = 'baz'; print $foo" 有效,因为在这种情况下 ${"foo"} 现在等于 ${"test::foo"}。 Of Symbol Tables and Globs 有一些关于它的信息,高级 Perl 编程书也有。对不起我之前的错误。
        【解决方案11】:

        perldoc对我们有很好的定义。

        与 my 不同,它既为变量分配存储空间,又将简单名称与该存储空间相关联以在当前范围内使用,我们将简单名称与当前包中的包变量相关联,以在当前范围内使用。换句话说,our 与 my 具有相同的作用域规则,但不一定创建变量。

        【讨论】:

          【解决方案12】:

          Coping with Scoping 很好地概述了 Perl 范围规则。在正文中没有讨论our 已经足够老了。它在最后的Notes部分进行了说明。

          本文讨论了包变量和动态范围,以及它们与词法变量和词法范围的区别。

          【讨论】:

            猜你喜欢
            • 2011-01-08
            • 2020-10-15
            • 1970-01-01
            • 1970-01-01
            • 2016-02-20
            • 2013-07-16
            • 2010-12-23
            • 2011-01-18
            • 2011-01-17
            相关资源
            最近更新 更多