在使用JSON对象时,试图修改只读值

编程语言 2026-07-09

几年前我用JSON写过一些Perl代码。它在SLES15 SP6仍然可以工作,但在SLES15 SP7时我得到了如下错误:

尝试修改只读值时发生错误,出现在 (eval 73)[/usr/lib/perl5/vendor_perl/5.26.1/JSON.pm:287] 第63行。

相关的代码是:

use JSON -support_by_pp;
#...
use constant JSON_INDENT        => JSON->new(); # indenting JSONizer
JSON_INDENT->utf8(1);
JSON_INDENT->indent(1);
JSON_INDENT->indent_length(0);

如果我把最后一行注释掉,错误就不会再发生。

(我在代码中像 print JSON_INDENT->pretty->encode($JSON), "\n" 那样使用常量)

在SP升级时,我注意到了这些相关的变动: 添加了软件包 perl-JSON-XS-4.40.0-bp157.2.3.1.x86_64,并且将软件包 perl-Cpanel-JSON-XS4.37-bp156.2.3.1 升级到了 4.380.0-150700.3.3.1(两者都是 x86_64)。

问题出在哪里,应该如何解决?

相关的软件包代码是:

sub _load_xs {
    my ($module, $opt) = @_;
    __load_xs($module, $opt) or return;

    my $data = join("", <DATA>); # this code is from Jcode 2.xx.
    close(DATA);
    eval $data;
    JSON::Backend::XS->init($module);

    return 1;
};

第287行是 eval $data;

解决方案

如果你要定义一个常量,正如你在关于它的无数问题中已经注意到的那样,这是一种容易出错的做法,请一次性创建对象并设置它的所有状态:

BEGIN { $ENV{PERL_JSON_BACKEND} = 'JSON::PP' }
use JSON;

use constant JSON_INDENT => do {
    JSON->new->utf8(1)->indent(1)->indent_length(0);
    };

say JSON_INDENT->encode($hash);

不过,这也可以改成一个子例程(这正是 constant 为你所做的)。这实际上更像一个常量,因为你没有办法修改这个对象:

say JSON_INDENT($hash);
sub JSON_INDENT {
    state $json = JSON->new->utf8(1)->indent(1)->indent_length(0);
    $json->encode(@_);
    }

但你不需要调用子例程就能直接达到你想要的结果:

my $JSON_INDENT = JSON->new->utf8(1)->indent(1)->indent_length(0);
say $JSON_INDENT->encode($hash);

请选择不会引发问题的那个方案,而不是你选择的那个。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章