这样做,
print map { $_." x" => $_ } 1..5; print map { ("$_ x" => $_) } 1..5; print map { ("$_ x") => $_ } 1..5;
但是这会引发语法错误,
print map { "$_ x" => $_ } 1..5;
这是记录的bug,没有文档的错误,还是我看不懂为什么这不应该编译?
为什么perl认为这应该是映射EXPR,LIST而不是地图BLOCK LIST
解决方法
Why perl thinks this should be
map EXPR,LIST
instead ofmap BLOCK LIST
?
代码的相关部分在toke.c中,Perl的词法分析器(以下是Perl 5.22.0):
/* This hack serves to disambiguate a pair of curlies * as being a block or an anon hash. Normally,expectation * determines that,but in cases where we're not in a * position to expect anything in particular (like inside * eval"") we have to resolve the ambiguity. This code * covers the case where the first term in the curlies is a * quoted string. Most other cases need to be explicitly * disambiguated by prepending a "+" before the opening * curly in order to force resolution as an anon hash. * * XXX should probably propagate the outer expectation * into eval"" to rely less on this hack,but that could * potentially break current behavior of eval"". * GSAR 97-07-21 */ t = s; if (*s == '\'' || *s == '"' || *s == '`') { /* common case: get past first string,handling escapes */ for (t++; t < PL_bufend && *t != *s;) if (*t++ == '\\') t++; t++; } else if (*s == 'q') { if (++t < PL_bufend && (!isWORDCHAR(*t) || ((*t == 'q' || *t == 'x') && ++t < PL_bufend && !isWORDCHAR(*t)))) { /* skip q//-like construct */ const char *tmps; char open,close,term; I32 brackets = 1; while (t < PL_bufend && isSPACE(*t)) t++; /* check for q => */ if (t+1 < PL_bufend && t[0] == '=' && t[1] == '>') { OPERATOR(HASHBRACK); } term = *t; open = term; if (term && (tmps = strchr("([{< )]}> )]}>",term))) term = tmps[5]; close = term; if (open == close) for (t++; t < PL_bufend; t++) { if (*t == '\\' && t+1 < PL_bufend && open != '\\') t++; else if (*t == open) break; } else { for (t++; t < PL_bufend; t++) { if (*t == '\\' && t+1 < PL_bufend) t++; else if (*t == close && --brackets <= 0) break; else if (*t == open) brackets++; } } t++; } else /* skip plain q word */ while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF)) t += UTF8SKIP(t); } else if (isWORDCHAR_lazy_if(t,UTF)) { t += UTF8SKIP(t); while (t < PL_bufend && isWORDCHAR_lazy_if(t,UTF)) t += UTF8SKIP(t); } while (t < PL_bufend && isSPACE(*t)) t++; /* if comma follows first term,call it an anon hash */ /* XXX it could be a comma expression with loop modifiers */ if (t < PL_bufend && ((*t == ',' && (*s == 'q' || !isLOWER(*s))) || (*t == '=' && t[1] == '>'))) OPERATOR(HASHBRACK); if (PL_expect == XREF) { block_expectation: /* If there is an opening brace or 'sub:',treat it as a term to make ${{...}}{k} and &{sub:attr...} dwim. Otherwise,treat it as a statement,so map {no strict; ...} works. */ s = skipspace(s); if (*s == '{') { PL_expect = XTERM; break; } if (strnEQ(s,"sub",3)) { d = s + 3; d = skipspace(d); if (*d == ':') { PL_expect = XTERM; break; } } PL_expect = XSTATE; } else { PL_lex_brackstack[PL_lex_brackets-1] = XSTATE; PL_expect = XSTATE; }
说明
如果开头卷曲之后的第一个术语是一个字符串(以“,”或“”分隔开)或以大写字母开头的一个虚拟字,而下列术语是或=>,则将卷曲视为匿名哈希(这就是OPERATOR(HASHBRACK);意思).
其他情况对我来说有点困难.我通过gdb运行以下程序:
{ (x => 1) }
最后在最后的其他块:
else { PL_lex_brackstack[PL_lex_brackets-1] = XSTATE; PL_expect = XSTATE; }
可以说,执行路径明显不同;它最终被解析为一个块.