为什么“keys ::”不是语法错误?

时间:2016-06-30 13:21:55

标签: perl

我更多地出于好奇而尝试了下面的单行,并且感到惊讶的是它实际上没有 % sigil

$ perl -E 'say for keys ::'

适用于版本5.8.8和5.16.3;虽然后一版本会发出此警告:

  

Hash%::在-e第1行缺少keys()参数中的%。

这怎么工作?即使没有印记,%::允许它运行和打印密钥有什么特别之处?

请注意,密钥不会打印%main::

$ perl -E 'say for keys main::'
Hash main:: missing the % in argument 1 of keys() at -e line 1.

2 个答案:

答案 0 :(得分:6)

TL; DR

::并不特别;在Perl 5.22.0之前,您可以省略%并将任何标识符传递给keys

然而:

  • keys main::相当于keys %{'main'}或仅keys %main
  • keys ::相当于keys %{'::'}keys %::%main::(但不是%main)是{{的别名1}}。

相关代码在toke.c中(以下是5.8.8):

%::

/* Look for a subroutine with this name in current package, unless name is "Foo::", in which case Foo is a bearword (and a package name). */ if (len > 2 && PL_tokenbuf[len - 2] == ':' && PL_tokenbuf[len - 1] == ':') { if (ckWARN(WARN_BAREWORD) && ! gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVHV)) Perl_warner(aTHX_ packWARN(WARN_BAREWORD), "Bareword \"%s\" refers to nonexistent package", PL_tokenbuf); len -= 2; PL_tokenbuf[len] = '\0'; gv = Nullgv; gvp = 0; } else { len = 0; if (!gv) gv = gv_fetchpv(PL_tokenbuf, FALSE, SVt_PVCV); } /* if we saw a global override before, get the right name */ if (gvp) { sv = newSVpvn("CORE::GLOBAL::",14); sv_catpv(sv,PL_tokenbuf); } else { /* If len is 0, newSVpv does strlen(), which is correct. If len is non-zero, then it will be the true length, and so the scalar will be created correctly. */ sv = newSVpv(PL_tokenbuf,len); } 是当前令牌的长度。

  • 如果令牌为len,则会创建一个新标量,其PV(字符串组件)设置为main::

  • 如果令牌为main,则会使用::获取typeglob。

gv_fetchpv位于gv.c中,具有处理gv_fetchpv的特殊逻辑:

::

这将获取存储在密钥if (*namend == ':') namend++; namend++; name = namend; if (!*name) return gv ? gv : (GV*)*hv_fetch(PL_defstash, "main::", 6, TRUE); 下的default stash中的typeglob(即typeglob main::)。

最后,*main::期望它的参数是一个哈希值,但是如果你传递一个标识符,它会将它视为哈希的名称。请参阅op.c中的keys

Perl_ck_fun

这也适用于case OA_HVREF: if (kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) { char *name = SvPVx(((SVOP*)kid)->op_sv, n_a); OP * const newop = newHVREF(newGVOP(OP_GV, 0, gv_fetchpv(name, TRUE, SVt_PVHV) )); if (ckWARN2(WARN_DEPRECATED, WARN_SYNTAX)) Perl_warner(aTHX_ packWARN2(WARN_DEPRECATED, WARN_SYNTAX), "Hash %%%s missing the %% in argument %"IVdf" of %s()", name, (IV)numargs, PL_op_desc[type]); op_free(kid); kid = newop; kid->op_sibling = sibl; *tokid = kid; } else if (kid->op_type != OP_RV2HV && kid->op_type != OP_PADHV) bad_type(numargs, "hash", PL_op_desc[type], kid); mod(kid, type); break; 以外的其他内容:

::

As of 5.22.0,您不再允许省略$ perl -e'%h = (foo => "bar"); print for keys h' foo sigil。)

你也可以用B :: Concise看到这个:

%

答案 1 :(得分:0)

使用:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    /*
     * forget about the program name.
     */
    argv++;
    argc--;

    int i;
    unsigned int totalNumbers = 0;

    printf("Total number of arguments: %d\n", argc);

    for(i = 0; i < argc; i++) {
        printf("argv[%d]=%s\n", i, argv[i]);

        errno = 0;
        long num = strtol(argv[i], NULL, 10);
        if(!(num == 0L && errno == EINVAL))
            totalNumbers++;

    }
    printf("Total number of numeric arguments: %u\n", 
        totalNumbers);

    return 0;
}

说:

perl -MO=Deparse -E 'say for keys ::'

因此它在没有严格

的perl版本中对待:: as%::