gpt4 book ai didi

perl - 为什么 `join` 和/或 `JSON::to_json` 会默默地将我的数据从整数转换为字符串?

转载 作者:行者123 更新时间:2023-12-03 13:56:11 24 4
gpt4 key购买 nike

我不明白为什么join更改 JSON::to_string 的输出在以下示例中:

#!/usr/bin/perl
use v5.26;
use Data::Dumper;
use JSON;

my @version = (1, 2, 3, 4);

say "version: ", join ".", @version; # comment this line out

$Data::Dumper::Terse = 1;
$Data::Dumper::Indent = 0;

say Dumper(\@version);
say to_json(\@version);
包含 join 的行的输出:
version: 1.2.3.4
[1,2,3,4]
["1","2","3","4"]
但是用 join 注释掉这条线 to_json 的输出尽管 Data::Dumper 的输出突然显示整数而不是字符串还是一样的:
[1,2,3,4]
[1,2,3,4]

最佳答案

当您对数字进行字符串化时,字符串化与原始数字一起存储在标量中。 (您可以在我的答案底部看到一个演示。)
当您对字符串进行数字化时,数字化与原始数字一起存储在标量中。
这是一种优化,因为人们经常不止一次地对标量进行字符串化或数字化。
这对 Perl 来说不是问题,因为 Perl 具有强制运算符而不是多态运算符。但它使 JSON 序列化程序的作者处于需要额外信息或猜测应该使用标量包含哪些值的困难位置。
您可以使用 $x = 0 + $x; 强制输入一个数字.
您可以使用 $x = "$x"; 强制字符串.
更详细的答案如下。

Perl 可以自由地将内部格式更改为它认为合适的标量。这通常作为修改标量的一部分来完成。

$x = 123;          # $x contains a signed integer
$x += 0.1; # $x contains a float

$x = 2147483647; # $x contains a signed integer
++$x; # $x contains an unsigned integer (on a build with 32-bit ints)

$x = "123"; # $x contains a downgraded string
$x += 0; # $x contains a signed integer

$x = "abc"; # $x contains a downgraded string
$x .= "\x{2660}"; # $x contains an upgraded string
但有时,Perl 会为标量添加第二个值作为优化。
$x = 123;          # $x contains a signed integer
$x * 0.1; # $x contains a signed integer AND a float

$x = 123; # $x contains a signed integer
"$x"; # $x contains a signed integer AND a downgraded string

$x = "123"; # $x contains a downgraded string
$x+0; # $x contains a signed integer AND a downgraded string
这些不是您会遇到的唯一双(或三)变量。
my $x = !!0;        # $x contains a signed integer AND a float AND a downgraded string
"$!"; # $! contains a float (not a signed integer?!) AND a downgraded string
这在 Perl 中不是问题,因为我们使用类型强制运算符(例如 == 适用于数字, eq 适用于字符串)。但是许多其他语言依赖于多态运算符(例如 == 可用于比较字符串和比较数字)。 [1]
但它确实给 JSON 序列化器带来了一个问题,它们被迫将单一类型分配给标量。如果 $x既包含字符串又包含数字,应该使用哪一个?
如果标量是字符串化的结果,则使用数字是理想的,但如果标量是数字化的结果,则字符串是理想的。无法判断这些起源中的哪一个属于标量(如果有的话),因此该模块的作者面临一个艰难的选择。
理想情况下,他们会提供不同的接口(interface),但这可能会增加复杂性和性能损失。

您可以使用 Devel::Peek 的 Dump 查看标量的内部结构。 .相关行是 FLAGS线。
  • IOK没有 IsUV : 包含有符号整数
  • IOKIsUV : 包含一个无符号整数
  • NOK : 包含一个浮点数
  • POK没有 UTF8 : 包含降级字符串
  • POKUTF8 : 包含升级后的字符串
  • ROK : 包含引用

  • $ perl -MDevel::Peek -e'$x=123; Dump($x); "$x"; Dump($x);' 2>&1 |
    perl -M5.014 -ne'next if !/FLAGS/; say join ",", /\b([INPR]OK|IsUV|UTF8)/g'
    IOK
    IOK,POK

    $ perl -MDevel::Peek -e'$x="123"; Dump($x); 0+$x; Dump($x);' 2>&1 |
    perl -M5.014 -ne'next if !/FLAGS/; say join ",", /\b([INPR]OK|IsUV|UTF8)/g'
    POK
    IOK,POK
  • 好吧,Perl 没有针对不同数字类型的单独运算符,这可能会导致问题(例如,-0 存在浮点数,但不存在 int),但很少遇到这些问题。
    另一个问题是浮点数的字符串化通常会导致信息丢失。
  • 关于perl - 为什么 `join` 和/或 `JSON::to_json` 会默默地将我的数据从整数转换为字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65288524/

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