确实分配了子例程的结果,结果是数据的副本



我试图了解是否分配子例程的结果会导致该数据的复制。

sub maketext { 'text' };
my $foo = maketext();
my $foo_ref = $foo;
my $bar_ref = maketext();

在上面的示例中,$foo_ref的创建会比$bar_ref的创建更多的副本?

我该如何说服自己的等价或不等式?

数据副本似乎发生

sub maketext {
    my $text = 'text';
    say $text;
    return $text;
}
my $bar_ref = maketext();
say $bar_ref;

此打印

标量(0x11F5818)标量(0x11CFA68)

在子和 $bar_ref点中创建的数据的地址不相同。

在其表面上,随着函数返回数据,必须复制数据,并且对此进行了参考。

另一种可能性是,即使它不在范围之外,对原始数据的引用也被保留,就像它发生在封闭中一样。但是,这里的函数返回 first ,然后操纵其返回。因此,我看不出任何机制如何知道数据做了什么,因此数据被适当地复制。

您正在创建一个匿名标量引用,但从函数返回。


创建对标量的参考的一种方法,而无需附近的相应变量

my $scalar_ref = do { my $var };

或使用do { my $var },或者在您的情况下使用sub

sub anon_scalar_ref {
    # ...
    return my $var;
}

但是,我看不出您对此有什么用。也许你想做

sub maketext {
    # ... define $text ...
    return $text;
}

当您将其返回到变量时,没有额外的数据副本,因为它是返回的参考。

是的,它复制了。

use Devel::Peek qw( Dump );
sub maketext {
    my $text = 'text';
    Dump($text);
    return $text;
}
my $ref = maketext();
Dump($$ref);

输出:

SV = PV(0x8b18a0) at 0x8dbe38   <-- $text is at 0x8dbe38
  REFCNT = 1
  FLAGS = (POK,IsCOW,pPOK)
  PV = 0x8d9f70 "text"        <-- String buffer at 0x8d9f70
  CUR = 4
  LEN = 10
  COW_REFCNT = 1
SV = PV(0x8b1920) at 0x8b0cc8   <-- $$ref is at 0x8b0cc8
  REFCNT = 1
  FLAGS = (POK,IsCOW,pPOK)
  PV = 0x8d9f70 "text"        <-- String buffer at 0x8d9f70
  CUR = 4
  LEN = 10
  COW_REFCNT = 1

但是,由于复印件(cow)功能,并未复制字符串缓冲区。实际上,出于同样的原因进行my $text = 'text';时,它甚至没有复制。这意味着$text$$ref的常数都共享相同的字符串缓冲区(直到编辑了其中一个字符串缓冲区),即使它们完全不同。

您可以从使用lvalue sub复制返回值的情况下摆脱。

use Devel::Peek qw( Dump );
sub maketext :lvalue {
    my $text = 'text';
    Dump($text);
    return $text;
}
my $ref = maketext();
Dump($$ref);

输出:

SV = PV(0xe43c80) at 0xe6e238
[...]
SV = PV(0xe43c80) at 0xe6e238
[...]

perl 必须复制数据。否则对变量$foo的任何后续修改都将尝试修改字符串常数'text',这将导致您的代码死亡。

这就是

中发生的事情
for ( 'text' ) {
    $_ = 'test';
}

增加了错误

修改仅读取值

相关内容

最新更新