【问题标题】:Is the truthiness of a dualvar always that of its string part?双变量的真实性总是它的字符串部分吗?
【发布时间】:2019-05-29 09:28:55
【问题描述】:

我的 Perl 5.26.2 x64 (Cygwin) 的经验行为是,当且仅当其 string 部分为真时,对偶变量才是真:

# Falsy number, truthy string => truthy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 0, "foo"; say "yes" if $v'
yes

# Truthy number, falsy string => falsy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 1, ""; say "yes" if $v'

# Truthy number, truthy string => truthy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 1, "foo"; say "yes" if $v'
yes

# Falsy number, falsy string => falsy
$ perl -MScalar::Util=dualvar -E 'my $v=dualvar 0, ""; say "yes" if $v'

this 自 2009 年以来就是这种情况。

问题:这是有保证的行为吗?

  • Boolean::String 说这是行为。但是,就向后兼容性而言,我不知道这是否是我可以依赖的。 我也没有在perlsynScalar::Utilperldata#Context 中看到明确的声明。

  • 我确实在perldata#Scalar-values 中看到了以下内容:

    如果标量值未定义、空字符串或数字 0(或其等效字符串“0”),则标量值在布尔意义上被解释为 FALSE,如果是其他值,则被解释为 TRUE。布尔上下文只是一种特殊的标量上下文,它不会执行到字符串或数字的转换。

    不幸的是,“从未执行任何转换......”的声明并没有告诉我解释器正在查看的 dualvar 的哪个部分!

  • 同样,查斯。欧文斯的related answer

    真实性测试首先查看字符串

    但是如果它查看字符串first,它会查看second什么,什么时候?

编辑我的理解是,如果overload 定义在变量上,无论是否为双变量,bool 重载将控制。我想知道非重载的情况。

编辑 2 ikegami 的回答 here 指出 PL_sv_yesPL_sv_no 有一个 NV (double) 组件。对于奖励积分:),如果双变量有 NV 对真实性有任何影响吗? (让我知道该答案是否真的涉及到足以值得单独提出一个问题。)

【问题讨论】:

  • 这是我记得看过的最好的研究问题。
  • @zdim 感谢您的回答和赞美!

标签: perl language-lawyer boolean-expression truthiness


【解决方案1】:

是的,至少到目前为止。 SvTRUE_common 宏通常用于确定 SV 在布尔上下文中的“真”位置。以下是 perl 5.26.1 源代码中 sv.h 中的定义方式:

#define SvTRUE_common(sv,fallback) (            \
      !SvOK(sv)                     \
    ? 0                     \
    : SvPOK(sv)                     \
    ? SvPVXtrue(sv)                 \
    : (SvFLAGS(sv) & (SVf_IOK|SVf_NOK))         \
    ? (   (SvIOK(sv) && SvIVX(sv) != 0)     \
       || (SvNOK(sv) && SvNVX(sv) != 0.0))      \
    : (fallback))

标量通过SvOK 测试(是否已定义)后,下一个检查是SvPOK——标量是否具有有效的内部字符串表示。 Dualvars 总是通过这个检查,所以对 dualvar 的布尔测试是它的字符串表示是否为真 (SvPVXtrue(...))。

perl 5.6.2 中的代码不同

I32
Perl_sv_true(pTHX_ register SV *sv)
{
    if (!sv)
        return 0;
    if (SvPOK(sv)) {
        register XPV* tXpv;
        if ((tXpv = (XPV*)SvANY(sv)) &&
                (tXpv->xpv_cur > 1 ||
                (tXpv->xpv_cur && *tXpv->xpv_pv != '0')))
            return 1;
        else
            return 0;
    }
    else {
        ...

但逻辑是一样的——先检查SvPOK,然后返回字符串表示是否不为空且不等于"0"

我认为未来几代 Perl 开发人员会警惕改变这种长期存在的逻辑。

【讨论】:

  • 我认为原因是像abc(这是真的)这样的字符串会变成0(这是错误的)。因此,如果一个标量包含一个字符串及其数字化,则检查该字符串可确保正确的结果
  • mob,谢谢你的详细信息!也感谢 mob-rule.com,这很酷!
【解决方案2】:

问题:这是有保证的行为吗?

这归结为如何在布尔上下文中测试标量,作为字符串还是数字?

在 Perl 中,文档是最接近标准的东西。因此,如果文档中没有声明,那么正式的答案必须是:不,它不是“保证行为”。

由于文档数次非常接近,谈论上下文和转换,但具体说明完成了哪个测试,我会说这确实必须被视为实施细节。你不能“依赖”它。

如果需要严格的可靠性,一个解决方案是一个简单的类,确保测试您需要的东西。

在更实际的情况下,if ($v) 似乎是测试的字符串部分,如果不存在则进行数字测试(没有文档所说的实际转换)。当您询问已设置为 dualvar 的变量时,对于那些将成为字符串测试的变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 2014-08-04
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多