[英]Why is “keys ::” not a syntax error?
I tried the following one-liner more out of curiosity than anything and was surprised that it actually worked without the %
sigil. 我出于好奇而尝试了下面的单行程,并且很惊讶它实际上没有
%
sigil。
$ perl -E 'say for keys ::'
It works on both versions 5.8.8 and 5.16.3; 它适用于5.8.8和5.16.3版本; though the latter version emits this warning:
虽然后一版本发出此警告:
Hash %:: missing the % in argument of keys() at -e line 1.
Hash%::在-e第1行中缺少keys()参数中的%。
How does this even work? 这怎么工作? What is so special about
%::
that allows it to run and print its keys, even without the sigil? 有什么特别的关于
%::
允许它运行和打印它的键,即使没有sigil?
Note that the keys do not get printed with %main::
. 请注意,键不会使用
%main::
打印。
$ perl -E 'say for keys main::'
Hash main:: missing the % in argument 1 of keys() at -e line 1.
::
isn't special; ::
不是特别的; prior to Perl 5.22.0, you can omit the %
and pass any identifier to keys
. 在Perl 5.22.0之前,您可以省略
%
并将任何标识符传递给keys
。
However: 然而:
keys main::
is equivalent to keys %{'main'}
or just keys %main
keys main::
相当于keys %{'main'}
或只是keys %main
keys ::
is equivalent to keys %{'::'}
or just keys %::
. keys ::
相当于keys %{'::'}
或只是keys %::
。 %main::
(but not %main
) is an alias for %::
. %main::
:(但不是%main
)是%::
的别名。 The relevant code is in toke.c (the following is from 5.8.8): 相关代码在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
is the length of the current token. len
是当前令牌的长度。
If the token is main::
, a new scalar is created with its PV (string component) set to main
. 如果令牌是
main::
,则创建一个新的标量,其PV(字符串组件)设置为main
。
If the token is ::
, a typeglob is fetched with gv_fetchpv
. 如果令牌是
::
,则使用gv_fetchpv
获取gv_fetchpv
。
gv_fetchpv
lives in gv.c and has special logic for handling ::
: gv_fetchpv
存在于gv.c中,并具有处理::
特殊逻辑:
if (*namend == ':')
namend++;
namend++;
name = namend;
if (!*name)
return gv ? gv : (GV*)*hv_fetch(PL_defstash, "main::", 6, TRUE);
This fetches the typeglob stored in the default stash under key main::
(ie typeglob *main::
). 这将获取存储在密钥
main::
:(即typeglob *main::
:)下的默认存储区中的 typeglob。
Finally, keys
expects its argument to be a hash, but if you pass it an identifier, it treats it as the name of a hash. 最后,
keys
期望它的参数是一个哈希值,但如果你传递一个标识符,它会将它视为哈希的名称。 See Perl_ck_fun
in op.c: 请参阅
Perl_ck_fun
中的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;
This works for things other than ::
, too: 这适用于除了
::
之外的其他东西:
$ perl -e'%h = (foo => "bar"); print for keys h'
foo
( As of 5.22.0 , you're no longer allowed to omit the %
sigil.) ( 截至5.22.0 ,您不再被允许省略
%
sigil。)
You can also see this with B::Concise: 你也可以用B :: Concise看到这个:
$ perl -MO=Concise -e'keys main::'
Hash %main missing the % in argument 1 of keys() at -e line 1.
6 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
5 <1> keys[t2] vK/1 ->6
4 <1> rv2hv[t1] lKRM/1 ->5
3 <$> gv(*main) s ->4
-e syntax OK
$ perl -MO=Concise -e'keys ::'
Hash %:: missing the % in argument 1 of keys() at -e line 1.
6 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
5 <1> keys[t2] vK/1 ->6
4 <1> rv2hv[t1] lKRM/1 ->5
3 <$> gv(*main::) s ->4
-e syntax OK
Using: 使用:
perl -MO=Deparse -E 'say for keys ::'
Says: 说:
use feature 'current_sub', 'evalbytes', 'fc', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
say $_ foreach (keys %main::);
So it treats :: as %:: in these perl versions without a strict 因此它在没有严格的perl版本中对待:: as%::
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.