【问题标题】:How do I compare two objects in Perl without coercing them to the same type?如何在 Perl 中比较两个对象而不将它们强制为相同类型?
【发布时间】:2023-03-25 10:05:01
【问题描述】:

在 Perl 中,我知道三种测试对象是否相等的方法:==eq~~。所有这些都告诉我1 等于Perl 5 中的"1"

但是,1"1" 不是一回事。如何比较两个对象以使1 等于1"1" 等于"1"1 不等于"1"2,并且"1" 不等于"01"?两个 Perls 的答案将不胜感激。

【问题讨论】:

标签: perl


【解决方案1】:

不要。在 Perl 中,oneone。基于值类型的多态性必然会失败。这就是 Perl 有两个比较运算符的原因,这就是为什么 ~~ 被破坏的原因[1]

例如!0返回的标量包含三个值,存储为整数,存储为浮点数, 存储为字符串。

例如,package Foo; use overload '0+' => sub { 1 }, fallback => 1; 类的对象可能根本不包含 one,但在数字和字符串上下文中它被认为是 one


  1. 这就是它仍被标记为实验性的原因。

【讨论】:

  • 非常感谢。我觉得我现在对 Perl 有了更多的了解。我只提到了~~,因为我最近一直在尝试使用 Perl 6 而不是 Perl 5。
  • 我不知道 Perl 6,答案可能完全不同。这就是为什么我删除了您问题的 Perl 6 部分。随意提出关于 Perl 6 的相同问题作为单独的问题。
  • 一个并不总是一个:perl -E'say( (1 & "") eq ("1" & "") ? "eq" : "!eq")'
  • @ysth,是的,那个运营商违反了规则,但这样做会导致无数问题。这加强了我的回答。
【解决方案2】:

Data::Dumper::DumperJSON::encode_json 这样的序列化器可以将内部存储为数字differently 的标量从内部存储为字符串的标量中处理,因此您可以比较序列化的输出:

use Data::Dumper;
$x = 1;
$y = "1";
$same = Dumper($x) eq Dumper($y);

【讨论】:

  • 这可能会导致不同 Perl 版本中的不同行为,但是,如果您在转储变量之前对变量进行更复杂的处理。
  • 我同意@choroba,只需在数字上下文中使用字符串就可以改变Data::Dumper 的输出。 perl -MData::Dumper -e 'my $x="1"; print Dumper($x); $x==1 and print Dumper($x)' 打印 $VAR1 = '1'; $VAR1 = 1;
  • 大多数用户,大多数时候,不应该担心他们的标量的内部表示或依赖它们具有任何特定的内部表示。无论出于何种原因——也许是一个很好的理由,也许不是一个很好的理由——OP 正在担心它,而查看 Dumper 输出是访问它的方法之一。
  • @mob 我完全同意用户通常不必担心内部表示,当有人尝试自己实现 Dumper 或当他们'重新为他们的实际问题寻找错误的解决方案。但是,我不同意“查看 Dumper 输出是访问它的一种方式”,原因很简单,我在上面展示了 (see also)。通常,Scalar::Util::looks_like_number 可能是一个很好的解决方案。
  • 他们通过强加一组任意规则来“解决”这个问题,这些规则导致的值与它们在 Perl 中可能出现的值不同。例如perl -MJSON -le'$!=5; print JSON->new->encode([$!]); print $! == 5;'
【解决方案3】:

您可以使用这个 sn-p 作为比较函数的起点:

my $num = 42;
my $str = "42";
say B::svref_2object(\$num)->FLAGS;
say B::svref_2object(\$str)->FLAGS;

您会看到两个变量的标志不同。阅读perldoc B 了解更深入的信息。

您可能还会发现JSON::PP 的源代码很有趣。搜索“sub value_to_json”。

【讨论】:

  • 魔法变量失败(例如${\substr("abc",1,1)},最初)。
  • 重载对象失败。
  • 不处理包含以下一项以上的标量:字符串、整数和浮点数。 (例如!1)。
  • 起点 ...我将更新答案并将 OP 指向 JSON::PP,它解决了您提到的许多问题。
  • 它通过强加一组任意规则来“解决”这个问题,这些规则导致的值与它们在 Perl 中可能出现的值不同。例如perl -MJSON::PP -le'$!=5; print JSON::PP->new->encode([$!]); print $! == 5;'
猜你喜欢
  • 1970-01-01
  • 2019-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-12-29
相关资源
最近更新 更多