为何Perl中sort List::Util::uniq与sort &List::Util::uniq行为不同?
两段Perl代码的差异解析
核心问题:Perl对sort语法的解析优先级
你遇到的问题本质不是函数原型的禁用,而是Perl解析sort语句时的优先级规则,导致两段代码的执行逻辑完全不同:
第一段代码的实际行为
use constant FOOBAR => sort List::Util::uniq(FOO, BAR);
Perl会把这句解析成 sort SUBNAME LIST 的形式:
- 把
List::Util::uniq当作排序比较函数(而非先调用它) - 把
(FOO, BAR)当作要排序的原始列表
但uniq的设计是接收一个列表返回去重结果,根本不是排序用的比较函数(比较函数需要接收两个参数,返回-1/0/1表示元素大小关系)。用它当比较函数会完全混乱:每次比较时,uniq会收到FOO和BAR对应的两个列表,返回去重后的列表,sort会把这个列表错误地当成比较结果处理,最终得到不符合预期的输出。
第二段代码的实际行为
use constant FOOBAR => sort &List::Util::uniq(FOO, BAR);
使用&调用函数时,Perl会优先执行&List::Util::uniq(FOO, BAR)这个表达式:
- 先把FOO和BAR的列表合并,传给
uniq去重,得到去重后的列表 - 再用
sort对这个去重后的列表进行默认排序
这才是你预期的“去重后排序”逻辑。
关于“括号禁用原型”的误解
你提到的“括号禁用原型”只适用于未预先声明/导入原型的函数。对于List::Util::uniq这种已经明确有@原型(接收一个扁平列表)的函数,带括号的调用uniq(FOO, BAR)并不会禁用原型——Perl依然会按照原型把FOO和BAR的列表合并成一个扁平列表传给uniq。但这里的核心矛盾不是原型,而是sort的解析优先级。
让第一段代码符合预期的修改
如果想不用&也实现同样效果,需要明确告诉Perl先执行uniq调用,比如:
# 用括号包裹整个函数调用,强制优先执行 use constant FOOBAR => sort( List::Util::uniq(FOO, BAR) ); # 或者用+符号,把函数调用标记为表达式 use constant FOOBAR => sort +List::Util::uniq(FOO, BAR);
内容的提问来源于stack exchange,提问作者Evan Carroll
相关产品推荐
相关产品推荐

