【问题标题】:Why does perl only dereference the last index when the range operator is used?为什么 perl 只在使用范围运算符时取消引用最后一个索引?
【发布时间】:2015-07-23 01:39:21
【问题描述】:

我有一个数组引用数组@array。如果我使用范围运算符打印@arrayprint @array[1..3] 的元素 1 到 3,perl 会打印元素 1 到 3 的数组引用。

为什么当我尝试取消引用索引在 1 和 3 之间的数组引用时,@{@array[1..3]},perl 只取消引用并打印出范围运算符中索引的最后一个元素?

有没有办法在取消引用数组时使用范围运算符?

示例代码

#!/bin/perl

use strict;
use warnings;

my @array = ();
foreach my $i (0..10) {
    push @array, [rand(1000), int(rand(3))];
}

foreach my $i (@array) {
    print "@$i\n";
}

print "\n\n================\n\n";

print @{@array[1..3]};

print "\n\n================\n\n";

【问题讨论】:

    标签: perl


    【解决方案1】:

    来自perldata

    标量上下文中的切片返回切片的最后一项。

    @{ ... }scalar 值作为数组解引用,这意味着被解引用的值在标量上下文中。从上面的 perldata 引用我们知道这将返回最后一个元素。因此结果是最后一个元素。

    更合理的方法是遍历切片并打印每个单独的数组引用:

    use strict; 
    use warnings; 
    
    use feature qw(say);
    
    my @array_of_arrayrefs = (
       [qw(1 2 3)],
       [qw(4 5 6)],
       [qw(7 8 9)],
       [qw(a b c)],
    );
    
    foreach my $aref ( @array_of_arrayrefs[1..3] ) {
       say join ',', @$aref;
    }
    

    【讨论】:

      【解决方案2】:

      @{@array[1..3]} 是一个看起来很奇怪的构造。 @{ ... } 是数组取消引用运算符。它需要一个引用,这是一种标量。但是@array[ ... ] 会生成一个列表。

      这是您需要记住标量上下文中列表评估规则的情况之一。规则是没有一般规则。每个生成列表的运算符都做自己的事情。在这种情况下,显然标量上下文中使用的数组切片运算符返回列表的最后一个元素。标量上下文中的@array[1..3]$array[3] 相同。

      正如您所注意到的,这没有用。数组切片不适用于标量上下文

      如果要将二维嵌套数组结构展平为一维列表,请使用map

      print join ' ', map { @$_ } @array[1..3]
      

      您仍然使用范围运算符进行切片。您只需要某种循环结构(例如map)即可将数组取消引用运算符分别应用于外部数组的每个元素。

      【讨论】:

      • “规则是没有一般规则” 这不是真的。标量上下文中的 list 计算结果为列表的最后一个元素。标量上下文中的 array 计算为数组中元素的数量。
      • @Borodin, Re > 那么一般规则是什么?您只提到了两个特定的运算符。什么一般规则涵盖了其他 100 条规则? OP 使用的那个(数组切片)呢?问题是,Wumpus 是正确的。 There isn't a general rule.
      • 我在引用 perlfunc 本身(大约,从记忆中)。这是确切的句子:There is no rule that relates the behavior of an expression in list context to its behavior in scalar context, or vice versa.
      • @Borodin,关于“我没有提到任何运算符”,您给出了列表运算符和数组运算符的行为,同时错误地声称有一个通用规则来控制运算符在标量上下文中返回的内容。 不可能预测运算符在标量上下文中的行为;没有任何规则或指导方针可以提供帮助。
      • @Borodin,是的,但是他们通过学习或查找这些运算符在标量上下文中的行为方式来做到这一点,而不是通过学习一些不存在的规则。 (除了显而易见的:如果一个运算符通常在列表上下文中返回一个标量,它会在标量上下文中返回相同的标量)
      【解决方案3】:

      @{ ... } 构造将大括号内代码的标量值取消引用为数组

      我不清楚您对 @{ @array[1..3] } 的期望,但 标量上下文 中的 list@array[1..3] 仅返回列表的最后一个元素 -- $array[3] -- 所以您在问对于@{ $array[3] },我猜这就是你得到的

      如果您解释要打印的内容,那么我相信我们可以提供帮助,但取消引用列表没有意义

      【讨论】:

      • @array[1..3] 不是列表;这是一个数组切片。在列表上下文中,它返回将在列表上下文中返回的最后一个标量。这实际上与标量上下文中的列表不同。
      • "在列表上下文中,它返回在列表上下文中返回的最后一个标量" 嗯,它是 i> 在列表上下文中。你想重写吗?
      • s/在列表上下文中/在标量上下文中/
      【解决方案4】:

      @array[1..3] 是一个包含 3 个数组引用的列表。您不能一次全部取消引用,因此您应该遍历此列表并分别取消引用每个元素:

      print @$_ for @array[1..3];
      print "@$_\n" for @array[1..3];  # for better looking output
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-05
        • 2018-07-28
        • 2019-03-19
        • 2018-03-27
        • 2020-04-01
        • 2020-12-12
        • 1970-01-01
        相关资源
        最近更新 更多