分配子程序的结果是否会导致数据的副本?
Does assigning the result of a subroutine result in a copy of the data?
我想了解分配子例程的结果是否会导致复制该数据。
sub maketext { 'text' };
my $foo = maketext();
my $foo_ref = $foo;
my $bar_ref = \maketext();
在上面的例子中,创建$foo_ref
会比创建$bar_ref
多一份吗?[=13=]
我怎样才能说服自己他们是等价的还是不等价的?
似乎发生了数据复制
sub maketext {
my $text = 'text';
say $text;
return $text;
}
my $bar_ref = \maketext();
say $bar_ref;
这会打印
SCALAR(0x11f5818)
SCALAR(0x11cfa68)
sub中创建的数据地址和$bar_ref
指向的地址不一样。
从表面上看,作为函数 returns,必须复制数据,并获取对它的引用。
另一种可能性是对原始数据的引用即使超出范围也会保留,就像它发生在闭包中一样。但是,这里函数 returns first 及其 return 然后被操作。所以我看不出任何机制如何知道对数据做了什么,所以数据被适当地复制了。
您正在创建匿名标量引用,但在函数 return 之外。
一种在没有相应变量的情况下创建对标量的引用的方法是
my $scalar_ref = \do { my $var };
或 do { \my $var }
,或者你的情况是
sub anon_scalar_ref {
# ...
return \my $var;
}
但是,我看不出你要这个有什么用。也许你想做
sub maketext {
# ... define $text ...
return $text;
}
当您将此 return 分配给变量时,不会生成额外的数据副本,因为它是 returned 的引用。
Perl 必须复制 数据。否则,对变量 $foo
的任何后续修改都将尝试修改字符串常量 'text'
,这将导致您的代码终止。
这就是
中发生的事情
for ( 'text' ) {
$_ = 'test';
}
引发错误
Modification of a read-only value attempted
是的,它复制了。
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"[=11=] <-- 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"[=11=] <-- String buffer at 0x8d9f70
CUR = 4
LEN = 10
COW_REFCNT = 1
但是,由于写时复制 (COW) 功能,字符串缓冲区不会被复制。事实上,出于同样的原因,当您执行 my $text = 'text';
时,它甚至没有被复制。这意味着常量 $text
和 $$ref
都共享同一个字符串缓冲区(直到它们的一个字符串缓冲区被编辑),即使它们是完全不同的标量。
您可以通过使用左值子来避免复制返回值。
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
[...]
我想了解分配子例程的结果是否会导致复制该数据。
sub maketext { 'text' };
my $foo = maketext();
my $foo_ref = $foo;
my $bar_ref = \maketext();
在上面的例子中,创建$foo_ref
会比创建$bar_ref
多一份吗?[=13=]
我怎样才能说服自己他们是等价的还是不等价的?
似乎发生了数据复制
sub maketext {
my $text = 'text';
say $text;
return $text;
}
my $bar_ref = \maketext();
say $bar_ref;
这会打印
SCALAR(0x11f5818) SCALAR(0x11cfa68)
sub中创建的数据地址和$bar_ref
指向的地址不一样。
从表面上看,作为函数 returns,必须复制数据,并获取对它的引用。
另一种可能性是对原始数据的引用即使超出范围也会保留,就像它发生在闭包中一样。但是,这里函数 returns first 及其 return 然后被操作。所以我看不出任何机制如何知道对数据做了什么,所以数据被适当地复制了。
您正在创建匿名标量引用,但在函数 return 之外。
一种在没有相应变量的情况下创建对标量的引用的方法是
my $scalar_ref = \do { my $var };
或 do { \my $var }
,或者你的情况是
sub anon_scalar_ref {
# ...
return \my $var;
}
但是,我看不出你要这个有什么用。也许你想做
sub maketext {
# ... define $text ...
return $text;
}
当您将此 return 分配给变量时,不会生成额外的数据副本,因为它是 returned 的引用。
Perl 必须复制 数据。否则,对变量 $foo
的任何后续修改都将尝试修改字符串常量 'text'
,这将导致您的代码终止。
这就是
中发生的事情for ( 'text' ) {
$_ = 'test';
}
引发错误
Modification of a read-only value attempted
是的,它复制了。
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"[=11=] <-- 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"[=11=] <-- String buffer at 0x8d9f70
CUR = 4
LEN = 10
COW_REFCNT = 1
但是,由于写时复制 (COW) 功能,字符串缓冲区不会被复制。事实上,出于同样的原因,当您执行 my $text = 'text';
时,它甚至没有被复制。这意味着常量 $text
和 $$ref
都共享同一个字符串缓冲区(直到它们的一个字符串缓冲区被编辑),即使它们是完全不同的标量。
您可以通过使用左值子来避免复制返回值。
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
[...]