Perl 是一种具有明显上下文依赖性的语言:表达式的结果依赖于结果被如何使用。历史上这使得语言异常灵活,但即使是经验丰富的开发人员在不考虑标量和列表上下文的工作方式时也可能出错。
这个问题从 Perl 的第一个版本就出现了,当时假设同样的操作可以返回数组或单个值 —— 例如,调用 localtime 函数可能根据情况返回列表或字符串。
问题 在于,错误地处理上下文会导致意想不到的错误:例如,额外的元素、空结果或逻辑表达式的奇怪行为。
解决方案 是始终明确理解函数或表达式在何种上下文中被调用,使用内置函数 wantarray 在自己的子程序中,并且不允许隐式混合上下文。
代码示例:
sub may_return { return wantarray ? (1, 2, 3) : "scalar result"; } my @arr = may_return(); # 返回 (1,2,3) my $val = may_return(); # 返回 "scalar result"
关键特性:
能否在函数内部判定表达式是否在 void 上下文中使用?
答案:不能,只能是标量或列表。在 Perl 5 中没有函数能够在子程序内部定义 void 上下文 —— wantarray 在这种情况下返回 undef,但用于其他行为。
代码示例:
sub example { return wantarray ? (1,2) : wantarray ? undef : "scalar"; # 不正确 }
函数能否根据上下文返回不同类型的数据?
答案:是的,完全可以并且经常使用。
运算符的行为(例如,shift、pop)是否依赖于上下文?
答案:是的。例如,当 shift 在函数内部被调用时,依赖于 @_(全局或词法),结果是以标量还是列表的形式传递。
开发者写了一个总是返回列表的函数,没有考虑标量上下文。如果在标量上下文中调用此函数,将仅得到列表的最后一个元素。
优点:
缺点:
函数使用了 wantarray,并返回列表、一个有意义的标量或 undef。
优点:
缺点: