Perl 05:引用决定谁能改动同一份记录
03 的字符串数组复制没有改变原数组,但解析器里的一条日志是哈希引用。如果另一个阶段拿到的是同一引用,它改变记录的字段,后续报表会看到修改后的值。是否“复制成功”要看复制的是标量内容、容器,还是容器里的引用。
examples/perl-language/experiments/05-references.pl 做了两组对照。\@source 指向现有数组,[@source] 新建数组;两者初始内容相同。向前者追加 worker 后,原数组输出 source=api|worker;向新数组追加 cache,其输出 copy=api|cache,原数组并未得到 cache。随后把同一个哈希引用放入新数组,改其 label:原哈希输出 shared=changed。这并非矛盾:数组外壳是新建的,元素里保存的引用仍指向同一哈希。
图:数组外壳复制与元素引用共享
1 | |
命令 perl examples/perl-language/experiments/05-references.pl 的四行金标及 STDOUT/STDERR/退出码在 examples/perl-language/evidence/05-08.md;累计测试 t/05-08-boundaries.t 逐字节断言了两种共享方式。正式工具 read_records 返回数组引用,format_record 读一条哈希引用,这只约定了数据形状,不承诺调用者不能修改它。后面若要把解析与规范化阶段隔开,须明确所有权或复制边界,而不是写个 my @copy = @$records 就宣称深拷贝。
补充实验 course-semantics.pl refs 把引用身份写成五行:alias_level=WARN、copy_nested=1/9、autoviv_before=0 after=missing value=undef、local_nested_inside=WARN、local_nested_after=INFO next_batch=ERROR。第一行来自 $alias = $record 后改 $alias->{level},原记录随之变化;第二行来自显式复制内层哈希,修改副本的 nested.count 不再影响原记录;第三行留到 06 解释自动创建。后两行说明 local 对包变量里的嵌套元素做动态临时替换,离开块后恢复原会话值;另一个 batch 的哈希引用仍是独立容器,不会因为 local 的恢复规则自动继承或回滚。测试断言这些行,给“浅复制”“复制内层容器”和“动态恢复”划出可运行边界。
[PATTERN] 复制外壳只能隔离外壳,复制共享目标才隔离目标。{ %$record } 新建第一层哈希;若某个值仍是哈希引用,双方仍共享内层。要让规范化、筛选、报表互不污染,代码必须说明每一层是借用、共享还是复制。官方 perlref 的 Making References 与 Using References 只提供机制;所有权策略来自课程契约。
练习:把 push @$alias, 'worker' 改成 push @$copy, 'worker',原数组增加新元素吗?不会。若把一个哈希引用同时放进两个数组,修改该哈希会被另一方看到;拒绝可变共享需要复制哈希字段或限制写入。参考:Perl 5.38.2 校验过的上游发行包 pod/perlref.pod(Making References、Using References),pod/perldata.pod(List value constructors)。









