在Perl中,任何函数可以确定其调用的上下文:标量、列表或void。运算符wantarray用于确定上下文。
示例:
sub foo { if (wantarray) { return (1, 2, 3); # 列表 } else { return 42; # 标量 } } my @a = foo(); # (1, 2, 3) my $b = foo(); # 42 foo(); # Void context
特点:如果没有正确使用wantarray,可能会返回意外的值。
如果函数根据上下文返回数组和标量,而在void上下文中被调用,它会返回什么?
答案:在void上下文中,返回的值会被忽略,但根据wantarray的执行代码分支仍然存在。因此,应该考虑单独的处理,如果函数执行副作用。例如:
sub noisy { if (wantarray) { print "在列表上下文中被调用"; return (1,2,3); } elsif (defined wantarray) { print "在标量中被调用"; return 42; } else { print "Void!"; return; } }
故事 1
在项目中,一名工程师忘记了上下文的区别。一个返回文件名列表的函数,有时只返回文件数量(标量上下文),而不是实际的名称——这在与其他结果连接时导致数据丢失。
故事 2
在为解析头部设计API时,函数仅在左边显式存在数组时返回列表(
my @headers = parse_headers()),而如果调用为if (parse_headers())时,只返回第一个头部。这个bug并没有立即发现,因为处理看起来很合理——但在项目的不同部分的行为却有所不同。
故事 3
一个用于在文件中查找匹配项的函数根据上下文返回不同数量的结果。结果在传递给map或grep时发生了意想不到的错误:map期望一个列表,但得到了undef——而在标量上下文中只计算找到的匹配项的数量。这个问题直到经过几次发布才被发现。