为什么JSON编码需要引用Perl版本字符串?

Bru*_*len 2 oop perl json

对于某些 Perl 诊断测试,我使用 JSON::MaybeXS 记录格式化为 JSON 的各种信息。

当我想记录当前的 Perl 版本(从特殊变量 $^V 获取)时,出现错误。

正如最小的演示脚本所示,除非我将 $^V 引用为“$^V”,否则会发生错误。

json_perl_version_test.pl

#!/usr/bin/env perl

use strict;
use warnings;
use v5.18;

use JSON::MaybeXS;

say "Running Perl version $^V";

my $item    = 'Wut?';

my %hash1   = (
    something   => $item,
    v_unquoted => $^V
);
eval { say say 'Hash1: ', encode_json \%hash1 };
say "Oops - JSON encode error: $@" if $@;

my %hash2   = (
    something   => $item,
    v_quoted => "$^V"
);
say 'Hash2: ', encode_json \%hash2;

# Running Perl version v5.34.0
# Oops - JSON encode error: encountered object 'v5.34.0', 
# but neither allow_blessed, convert_blessed nor allow_tags
# settings are enabled (or TO_JSON/FREEZE method missing) at
# /Users/bw/Documents/Dev/tests/json_perl_version_test.pl line 17.

# Hash2: {"something":"Wut?","v_quoted":"v5.34.0"}

Run Code Online (Sandbox Code Playgroud)

请注意,不必引用 $item。

错误消息引用了一些处理其他情况的方法,但似乎不包括规范的 Perl 版本点分十进制字符串。我查看了主要的 Perl JSON 模块(JSON::MaybeXS、JSON 和 Cpanel::JSON::XS 的最新版本),但找不到任何引用 $^V 或点分十进制字符串的内容。也没有找到有关 SO 的相关问题:(。

也许我错过了什么?或者我是否需要引用 $^V ?

原因?

谢谢,

zdi*_*dim 5

变量$^V一个对象

\n
\n

Perl 解释器的修订版、版本和颠覆,以版本表示对象。

\n
\n

对象不能像这样存储在 JSON 中。引用它会将其字符串化。

\n
\n

可以使JSON::XS(及其Cpanel::)获得一个有福的参考,但它涉及更多的工作。请参阅对象序列化。最干净的完整解决方案是使用convert_blessed,当该encode方法将寻找TO_JSON方法(在要添加到JSON的对象的类中),该方法将返回一个JSON就绪字符串。

\n

唉,没有这样的东西version(也没有我尝试过的其他一些课程,比如DateTime)。可以将该方法添加到类\xe2\x80\xa0中中,但只要想到它就会使引号看起来很漂亮。

\n

另一种方法是明确地使version对象字符串化

\n
my $json = JSON::XS->new->encode( { ver => $^V->stringify } )\n
Run Code Online (Sandbox Code Playgroud)\n

这还更复杂,但至少现在很清楚问题是什么,不需要神奇的引号。

\n

或者只是引用它并添加评论。

\n
\n

\xe2\x80\xa0 例如,通过“猴子修补”它

\n
    \n
  • 添加具有完全限定名称的子项目

    \n
    perl -Mstrict -wE\'use JSON::XS; say $^V; \n    sub version::TO_JSON { return $_[0]->stringify }; \n    my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); \n    say $json\'\n
    Run Code Online (Sandbox Code Playgroud)\n

    还可以在运行时通过字符串添加子项eval,但这似乎不需要。

    \n
  • \n
  • 在运行时将代码引用写入类的符号表

    \n
    perl -wE\'use JSON::XS; say $^V; \n    *{"version"."::"."TO_JSON"} = sub { return $_[0]->stringify }; \n    $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); \n    say $json\'\n
    Run Code Online (Sandbox Code Playgroud)\n

    好吧,或者实际上strict我们需要允许符号引用

    \n
    perl -Mstrict -wE\'use JSON::XS; say $^V; \n    NO_STRICT_REFS: { \n        no strict "refs"; \n        my ($class, $method) = qw(version TO_JSON);\n        *{$class."::".$method} = sub { return $_[0]->stringify } \n    }; \n    my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); \n    say $json\'\n
    Run Code Online (Sandbox Code Playgroud)\n

    我还添加了类名和方法的变量,这不是必需的,但更好。

    \n

    这是为了更好地在Sub::Install中使用而打包的

    \n
    use Sub::Install;\nSub::Install::install_sub({\n    code => sub { ... }, into => $package, as => $subname\n});\n
    Run Code Online (Sandbox Code Playgroud)\n

    模块中有预期的默认值和更多内容。

    \n
  • \n
\n

或者,当然可以通过编写包装类或类似的类,但那是另一回事。

\n