什么时候使用花括号在Perl中解除引用是有利的?

时间:2017-05-18 21:15:36

标签: perl

我看到了一些像这样的代码〜

my @array = @{ $array_ref };

我发现如果将其更改为〜

,它的工作方式也是一样的
my @array = @$array_ref;

同样,这个〜

my %hash = (frogs => sub {print "Frogs\n"});
&{$hash{frogs}}();

与〜

的作用相同
%hash = (frogs => sub {print "Frogs\n"});
$hash{frogs}();

(虽然我最初尝试将&hash{frogs}();期望它起作用,但由于产生的错误我不理解 - 不应该将sigil对应于散列中被访问的内容,在这种情况下{{1} 1}}用于子程序?)

所以我想知道为什么这些片段的作者会用另一种方式写出来,当它是额外的字符而没有我能感知到的任何优势时。

这里发生了什么我没有注意到的事情?何时可能存在需要使用花括号而不仅仅是sigil的情况?

2 个答案:

答案 0 :(得分:7)

你正在混淆两个概念。

您需要了解的第一件事是有two syntaxes用于引用。

 "Block syntax"       "Arrow syntax"

 $BLOCK               EXPR->$*
 @BLOCK               EXPR->@*
 $BLOCK[$i]           EXPR->[$i]
 &BLOCK()             EXPR->()
 ...                  ...

此外,两种语法都可以使用它们。

您的数组示例是块语法可用的简化示例。如果块只包含一个简单的标量($ref),则可以省略curles。

${ $ref }                   # Can be simplified to $$ref
@{ $ref }                   # Can be simplified to @$ref
${ $ref }[$i]               # Can be simplified to $$ref[$i]
&{ $ref }()                 # Can be simplified to &$ref()

如果该块包含其他任何内容,则无法利用此简化。

@{ $refs{$key} }            # Can't be simplified
@{ f() }                    # Can't be simplified
@{ my $ref = f(); $ref }    # Can't be simplified

&{ $refs{$key} }()          # Can't be simplified
&{ f() }()                  # Can't be simplified
&{ my $ref = f(); $ref }    # Can't be simplified

另一方面,您的代码示例是从块语法切换到箭头语法的示例。这不是简化本身

"Block syntax"               "Arrow syntax"
&{ $hash{frogs} }()    ⇒     $hash{frogs}->()

您的代码参考示例也是箭头语法可用的简化示例。当箭头位于[...]{...}以及[...]{...}(...)之间时,箭头可以省略。

$ref->{$k}->[$i]            # Can be simplified to $ref->{$k}[$i]
$ref->{$k}->{$l}            # Can be simplified to $ref->{$k}{$l}
$ref->{$k}->()              # Can be simplified to $ref->{$k}()

$ref->[$i]->[$j]            # Can be simplified to $ref->[$i][$j]
$ref->[$i]->{$k}            # Can be simplified to $ref->[$i]{$k}
$ref->[$i]->()              # Can be simplified to $ref->[$i]()

最后,您应该使用哪个?

是否对块语法或箭头语法的选择是个人偏好之一,但通常遵循以下约定以最大化可读性:

  • 块语法是标量,数组和散列解引用的首选。

    $$ref                is generally preferred over     $ref->$*
    @$ref                is generally preferred over     $ref->@*
    %$ref                is generally preferred over     $ref->%*
    
  • 使用块语法时,如果可能,将省略curlies。

    $$ref                is generally preferred over     ${ $ref }
    @$ref                is generally preferred over     @{ $ref }
    %$ref                is generally preferred over     %{ $ref }
    
  • 箭头语法是数组元素,哈希元素和代码解引用的首选。

    $ref->[...]          is generally preferred over     $$ref[...]
    $ref->{...}          is generally preferred over     $$ref{...}
    $ref->(...)          is generally preferred over     &$ref(...)
    
  • 尽可能省略箭头本身,除非用于参考代码。

    $ref->[...][...]     is generally preferred over     $ref->[...]->[...]
    $ref->[...]{...}     is generally preferred over     $ref->[...]->{...}
    $ref->[...]->(...)   is generally preferred over     $ref->[...](...)
    $ref->{...}[...]     is generally preferred over     $ref->{...}->[...]
    $ref->{...}{...}     is generally preferred over     $ref->{...}->{...}
    $ref->{...}->(...)   is generally preferred over     $ref->{...}(...)
    
  • 块语法是数组切片和散列切片的首选。它的可读性远远低于箭头语法,但这些箭头语法需要Perl 5.24。

    @$ref[...]           is generally preferred over     $ref->@[...]
    @$ref{...}           is generally preferred over     $ref->@{...}
    

答案 1 :(得分:2)

您的代码 主要 供其他人和编译器/解释器阅读。初级程序员往往倾向于将他们的创作视为纯粹为了他们自己的消费,作为一种生活记事本,但是编写设计笔记确实有比用编程语言编码更好的方法。

它向(人类)读者清楚地解释了你的代码在做什么。你@$array_ref的例子(除非你真的需要两份相同的数据列表,否则没有意义)很好,但是你怎么读$$array_ref{key}

大多数人都没有在他们的头脑中保留运算符优先级表,因此通过编写$array_ref->{key}或{{更容易解释您的意图1}}取决于你的意思

鉴于你提到这个

${ $array_ref{key} }

我认为你正在阅读一些相当陈旧的东西,或者由一个对Perl特别不熟悉的人写的东西。只有当您将子例程称为第一类数据对象(例如获取引用)并且仅调用子例程时,&{$hash{frogs}}() 前缀才是必需的

Perl允许您在连续的结束和左括号之间省略间接运算符&,但它通常更清楚地包含它。我通常在卷括号和方括号(索引哈希值或数组)之间省略它,但保留它用于过程调用

我会将该行写为

->