【问题标题】:Accessing array when passed to subroutine as reference in Perl在 Perl 中作为引用传递给子例程时访问数组
【发布时间】:2018-07-28 23:35:15
【问题描述】:

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

示例 1:

sub array_contains
{
    my ($arr_ref, $search, $strict) = @_;
    if ($strict) {
        return (grep {$_ eq $search} @$arr_ref);
    } else {
        return grep {index($_, $search) != -1} @$arr_ref;
    }
}

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

示例 2:

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

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


Perl 专家能否解释一下,为什么它必须在第二个示例中 @{$_[0]} 而不能是 @$_[0],就像在第一个示例中一样,我使用了 @987654327 @。是否必须将@_ 分配给本地范围的变量?

【问题讨论】:

  • 你的“更简洁”的版本也更难读。对你的代码这样做没有任何好处,所以不要这样做。
  • @Borodin,谢谢。今后我会牢记这一点。

标签: perl pass-by-reference


【解决方案1】:

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

因为前缀解引用操作符解析容易混淆,我推荐使用自 Perl 5.24 起可用的后缀解引用语法。那么@{ $_[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;
}

【讨论】:

  • 感谢您的解释。我真的不想使用依赖项。
  • List::Util 是一个核心模块
  • 是的,没错,它从 5.007003 开始​​就在核心中。再次感谢!
【解决方案2】:

考虑这一点的方式是,解引用“运算符”比数组索引具有更高的“优先级”(在此处使用引号,因为解引用不是 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] 进行索引(尽管使用的是 @987654322 @ 语法,$$foo[0]${$foo}[0] 在这里更有意义)。仅在最后一个示例中,数组@foo 元素[0] 被访问first,然后then 该元素作为数组被取消引用,导致该数组的所有元素正在打印。 $_/@_ 的行为相同。

另请参阅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!"

【讨论】:

    猜你喜欢
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2012-05-18
    • 2021-03-09
    • 2014-07-04
    • 2013-12-24
    • 2017-07-18
    • 2011-01-06
    相关资源
    最近更新 更多