gpt4 book ai didi

Perl 分配给 pos 会触发副本吗?

转载 作者:行者123 更新时间:2023-12-03 16:56:18 28 4
gpt4 key购买 nike

是否分配给 pos在字符串中算作“写”,触发副本? (在 OS X 上使用 perl 5.26 测试)

我正在写一个小的词法工具。经常出现的一件事是搜索从给定偏移量开始的模式......如果有匹配的字符串,则返回匹配的字符串。

为了支持重复尝试使用 token ,我需要我的函数来设置 pos如果我们成功了,就在比赛之后;如果没有,就到我们开始搜索的地方。

例如

my $string = "abc";
consume($string, qr/b/, 1);
printf "%s\n", pos($string); # should print 2

pos($string) = 0; # reset the pos, just to demonstrate
# the intended behavior when there isn't a match

consume($string, qr/z/, 1);
printf "%s\n", pos($string); # should print 1

这是一个返回正确的东西但没有正确设置位置的实现。
package TokenConsume;
use strict;
use warnings;

use Exporter qw[import];
our @EXPORT_OK = qw[consume];

sub consume {
my ($str, $pat, $pos) = @_;
pos($str) = $pos;
my $out = undef;
if ($str =~ $pat) {
$out = substr $str, $-[0], ($+[0] - $-[0]);
pos($str) = $+[0];
} else {
pos($str) = $pos;
}
return $out;
}

这是模块测试套件中的示例测试
do {
my $str = "abc";
pos($str) = 0;
my $res = consume($str, qr/z/, 1);
is($res, undef, "non-first: failed match should capture nothing");
is(pos($str), 1, "non-first: failed match should return pos to beginning of search");
};

它失败并显示以下消息(另一个测试也失败):
#   Failed test 'non-first: failed match should return pos to beginning of search'
# at t/test_tokenconsume.t line 38.
# got: '0'
# expected: '1'
# Looks like you failed 2 tests of 7.

我可以通过传入一个字符串引用并稍微更改 API 来解决这个问题。这是完整性的新实现。
sub consume {
my ($str_ref, $pat, $pos) = @_;
pos($$str_ref) = $pos;
my $out = undef;
if ($$str_ref =~ $pat) {
$out = substr $$str_ref, $-[0], ($+[0] - $-[0]);
pos($$str_ref) = $+[0];
} else {
pos($$str_ref) = $pos;
}
return $out;
}

那么,这里发生了什么?为什么没有分配给 pos(...)除非我使用引用,否则传播回原始值?

最佳答案

Perl does assigning to pos trigger a copy?



Perl 5.20 引入了一种写时复制机制,它允许标量共享一个字符串缓冲区。

不,更改 pos($str)不会触发副本。
$ perl -MDevel::Peek -e'
$_="abcdef"; Dump($_);
pos($_) = 2; Dump($_);
pos($_) = 3; Dump($_);
$_ .= "g"; Dump($_);
' 2>&1 | grep -P '^(?:SV| FLAGS| PV)'

SV = PV(0x192ee10) at 0x196d4c8
FLAGS = (POK,IsCOW,pPOK)
PV = 0x1955140 "abcdef"\0

SV = PVMG(0x1985810) at 0x196d4c8
FLAGS = (SMG,POK,IsCOW,pPOK)
PV = 0x1955140 "abcdef"\0

SV = PVMG(0x1985810) at 0x196d4c8
FLAGS = (SMG,POK,IsCOW,pPOK)
PV = 0x1955140 "abcdef"\0

SV = PVMG(0x1985810) at 0x196d4c8
FLAGS = (SMG,POK,pPOK)
PV = 0x1962360 "abcdefg"\0

[为了便于阅读,在输出中添加了空白行。]

IsCOW 所示标志, $_与另一个标量(常量)共享其字符串缓冲区( PV)。分配给 pos不会改变这一点。附加到 $_另一方面,会导致字符串缓冲区被复制( 0x19551400x1962360IsCOW 标志丢失)。

Why isn't the assignment to pos(...) propagating back to the original value unless I use a reference?



因为如果更改一个变量( $str )会更改其他一些不相关的变量( $string ),那将是非常糟糕的!他们可能共享一个字符串缓冲区是一个不相关的实现细节。

也就是说,Perl 通过引用传递,所以 $_[0]$string 的别名(参数),所以分配给 pos($_[0])会同时改变 pos($_[0])pos($string) (同一个变量)。

关于Perl 分配给 pos 会触发副本吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46417712/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com