在Perl中作为参考传递给子例程时访问数组

时间:2018-02-18 16:56:31

标签: perl pass-by-reference

我有误解,在Perl中使用花括号和引用。 我已经构建了一个基本函数来检查数组是否包含值。

示例1:

sub array_contains
{
    return (!$_[2] ? 
       (grep {$_ eq $_[1]} @{$_[0]}) : 
       (grep {index($_, $_[1]) != -1} @{$_[0]})
    );
}

后来,我想让它看起来更简洁。

示例2:

@$_[0]

然后,我花了一些时间才意识到由于某些原因我无法使用@{$_[0]},就像在第一个示例中一样,并且必须使用@{$_[0]}

可以 Perl 专家解释一下,为什么它必须在第二个例子@$_[0]上,而不能是@$arr_ref,就像在第一个例子中一样,我用@_。将? How would you like to eject from create-react-native-app? (Use arrow keys) ❯ React Native: I'd like a regular React Native project. ExpoKit: I'll create or log in with an Expo account to use React Native and the Expo SDK. Cancel: I'll continue with my current project structure. 分配给本地范围的变量是否必须做任何事情?

2 个答案:

答案 0 :(得分:4)

考虑这一点的方法是解除引用“运算符”具有比数组索引更高的“优先级”(在此处使用引号,因为解除引用不是Perl的operator precedence table的正式部分)。

use warnings;
use strict;

my $foo = ['arrayref elem 0','arrayref elem 1'];
my @foo = (['array of arrayrefs elem 0',' one']);

print  @$foo[0] , "\n";  # prints "arrayref elem 0"

# is the same as
print @{$foo}[0], "\n";  # prints "arrayref elem 0"

# is NOT the same as
print @{$foo[0]}, "\n";  # prints "array of arrayrefs elem 0 one"

也就是说,在前两个示例中,首先将$foo中存储的数组引用解除引用为数组,然后然后该数组使用[0]进行索引(尽管使用slice语法,$$foo[0]${$foo}[0]会更有意义。)仅在最后一个示例中,数组@foo元素[0]首先访问 然后该元素作为数组解除引用,从而导致所有要打印的数组的元素。 $_ / @_的行为相同。

另请参阅Using References in perlref@{...}解除引用样式始终有效,而大括号在简单情况下可省略,例如@$arr_ref

如果您使用的是Perl 5.24或更新版本,则可以使用Postfix Dereference Syntax(5.20和5.22中为experimental):

use 5.024;
my @bar = (['Hello,',' World!']);
print $bar[0]->@*, "\n";  # prints "Hello, World!"

答案 1 :(得分:2)

@$arr@$_[0]中的前缀解除引用运算符绑定非常紧密 - 因此后者被解析为@{ $_ }[0]。这是一个数组切片,它使用$_作为数组引用。这与@_数组无关。一个元素的切片通常被写为标量访问${ $_ }[0]$_->[0]

因为前缀解引用运算符解析混乱,所以我推荐自Perl 5.24以来可用的postfix解引用语法。然后@{ $_[0] }可以写成$_[0]->@*

请注意,代码应为 clear ,不一定与 short 相同。命名您的参数而不是直接访问@_数组更易于维护。我只能直接访问@_,如果只有一个参数(例如在访问方法sub foo { shift->{foo} }中)或者我对代码进行基准测试并确定避免复制将节省我半微秒我真的需要。 (不经常发生。)

如果你的函数的目标是布尔检查而不是选择所有匹配的元素,我就这样写:

use List::Util 'any';

sub array_contains {
  my ($arr, $search, $is_strict) = @_;
  return any { $_ eq $search } @$arr if $is_strict;
  return any { -1 != index $_, $search } @$arr;
}