Perl:"变量不会保持共享"

jac*_*ter 16 variables perl local

我查了几个处理这个警告的答案,但他们也没有帮助我,也没有真正理解Perl在这里做的事情.这就是我想要做的事情:

sub outerSub {
  my $dom = someBigDOM;
  ...
  my $otherVar = innerSub();
  return $otherVar;

  sub innerSub {
    my $resultVar = doStuffWith($dom);
    return $resultVar;
  }
}
Run Code Online (Sandbox Code Playgroud)

基本上,我有一个存储在$ dom中的大DOM对象,如果可能的话我不想在堆栈中传递.在outerSub中,正在发生需要来自innerSub的结果的东西.innerSub需要访问$ dom.当我这样做时,我收到这个警告"变量$ dom将不会保持共享".

我不明白的是:

  1. 这个警告对我有疑虑吗?我的逻辑会在这里运作还是会发生奇怪的事情?

  2. 如果它不能按预期工作:是否可以这样做?使局部变量对嵌套子变得可见?或者将它作为参数传递更好?或者声明一个"我们的"变量是否更好?

  3. 如果我将它作为参数推送,整个对象及其所有数据(可能有几个MB)是否会被推入堆栈?或者我可以传递类似参考的东西?或者Perl是否将该参数作为参考单独处理?

  4. "变量$ foo将不会保持共享"Perl中的警告/错误在调用子例程时,有人会谈论一个匿名子,这将使这成为可能.我不明白它是如何工作的,从来没有使用过这样的东西.

  5. 我根本不理解这个解释(可能导致英语不是我的第一语言):"当调用内部子程序时,它将看到外部子程序变量的值,就像它在第一次调用外部子程序之前和期间一样. ;在这种情况下,在第一次调用外部子程序完成后,内部子程序和外部子程序将不再共享变量的公共值.":

"对外部子程序的第一次调用是完整的是什么意思?"
我的意思是:首先我称之为外部子程序.外部子调用内部子.外子当然还在运行.一旦外部子完成,内部子也将完成.那么当内部子已经完成时,这仍然适用于什么呢?那么"第一次"召唤呢?什么时候发生"第二次"通话......对不起,这个解释让我感到困惑.

对不起,有很多问题.也许有人至少可以回答其中一些问题.

yst*_*sth 16

简而言之,调用第二个及以后的outerSub将具有与innerSub使用的$ dom变量不同的$ dom变量.你可以通过这样做解决这个问题:

{
    my $dom;
    sub outerSub {
        $dom = ...
        ... innerSub() ...
    }
    sub innerSub {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

或通过这样做:

sub outerSub {
    my $dom = ...
    *innerSub = sub {
        ...
    };
    ... innerSub() ...
}
Run Code Online (Sandbox Code Playgroud)

或这个:

sub outerSub {
    my $dom = ...
    my $innerSub = sub {
        ...
    };
    ... $innerSub->() ...
}
Run Code Online (Sandbox Code Playgroud)

所有变量最初都是预先分配的,而innerSub和outerSub共享相同的$ dom.当你离开范围时,perl会遍历在范围中声明的词法变量并重新初始化它们.因此,当第一次调用outerSub完成时,它会得到一个新的$ dom.因为命名的subs是全局的东西,innerSub不受此影响,并且一直引用旧的$ dom.因此,如果第二次调用outerSub,则其$ dom和innerSub的$ dom实际上是单独的变量.

因此,将声明移出outerSub或使用匿名子(在运行时新近绑定到词法环境)可以解决问题.


per*_*eal 5

您需要有一个匿名子例程来捕获变量:

my $innerSub = sub  {
  my $resultVar = doStuffWith($dom);
  return $resultVar;
};
Run Code Online (Sandbox Code Playgroud)

例:

sub test {
    my $s = shift;

    my $f = sub {
        return $s x 2;
    };  

    print $f->(), "\n";

    $s = "543";

    print $f->(), "\n";
}

test("a1b");
Run Code Online (Sandbox Code Playgroud)

得到:

a1ba1b
543543
Run Code Online (Sandbox Code Playgroud)


Mig*_*Prz 5

如果您想最小化传递参数给 subs 的大小,请使用 Perl 引用。缺点/功能是 sub 可以更改引用的参数内容。

my $dom = someBigDOM;
my $resultVar = doStuffWith(\$dom);


sub doStuffWith {
   my $dom_reference = shift;
   my $dom_contents = $$dom_reference;
   #...
}
Run Code Online (Sandbox Code Playgroud)

  • 不,参数是通过副本传递的。如果你想要一个引用,你必须使用显式 Perl 引用(带反斜杠) (2认同)