编程全栈Perl开发人员

在Perl中有哪些参数传递到子程序的方法,以及如何组织引用传递?使用@_时有哪些细节,什么时候需要引用传递?

用 Hintsage AI 助手通过面试

回答

在Perl中,所有函数的参数通过数组@_进行处理。当调用子程序时,所有传递的参数都会进入这个数组,并且最初是一个列表,而不是副本,即如果你更改$_[0],你就是在修改原始值。

值传递:

sub foo { my ($arg1, $arg2) = @_; $arg1 = 10; # 只有局部变量被修改 }

引用传递:

sub bar { my ($array_ref) = @_; push @$array_ref, 42; } my @data = (1,2,3); bar(\@data); # @data 现在是 (1,2,3,42)

细节:

  • 如果你想要修改原始数组或散列,应该传递_引用_。
  • 在@_中的普通变量($foo, $bar)是原始参数的别名,但通过my ($a, $b) = @_解包时会创建副本。
  • 对于数组和散列,在普通传递时,它们的内容会展开为列表,你会失去边界:需要传递引用或使用特殊的shift技巧。

陷阱问题

如果在Perl中将数组传递给函数这样:myfunc(@arr),在函数内部访问$_[0],那里会是什么?

正确答案: 那里会是数组的第一个元素_值_,而不是指向整个数组的引用!要将数组作为整体对象传递,使用引用:myfunc(\@arr)

示例:

sub print_first { print $_[0], " "; } my @a = qw/foo bar baz/; print_first(@a); # 会输出'foo',而不是数组的引用 print_first(\@a); # 会输出ARRAY(0x...) — 指向整个数组的引用

历史

在一个项目中,我们调用函数来修改全局散列,像这样:update_hash(%global)。在函数内部修改了$_[0]。结果 — 只修改了参数数组的局部切片,而全局散列并未被修改。正确的解决方法是传递引用:update_hash(\%global)

历史

在编写API框架时,函数接收多个命名参数,使用散列。有时函数接收数组(但不是引用!),参数便混合在一起,导致困惑:myfunc(@arr, %opts)。结果发现部分散列键被数组值替换,而发现这个错误非常困难。

历史

在实现递归遍历树时,我们想要修改内部元素。函数接收数组“原样”,而不是引用。它们创建了副本,修改不会影响外部上下文。问题通过替换为引用传递的方式解决。