【问题标题】:Deferencing a subroutine syntax取消引用子例程语法
【发布时间】:2014-03-19 23:06:23
【问题描述】:

我想知道为什么下面的语法会失败

 #!/usr/bin/env perl

use warnings;
use strict;

sub add { return $_[0]+5; };
my $add_ref = \&add;

my $result = 0;

$result = &add(5);
print " result is $result \n";

$result = add(5);
print " result is $result \n";

#$result = $add_ref(5);  ---------------> fail
#print " result is $result \n";

#$result = {$add_ref}(5); -----------------> fail
#print " result is $result \n";

$result =  &{$add_ref}(5);
print " result is $result \n";

$result =  $add_ref->(5);
print " result is $result \n";

1) 我刚刚将函数add 的名称替换为{$add_ref},这是中级Perl 书中提到的方法。在函数调用中& 是可选的,但为什么在这种情况下不是。

2) 我还发现 $reference_to_anonymous_subroutine(parameter) 有效,但 $reference_to_names_subroutine(parameter) 无效

例子

my @array = (1, sub { my $n = $_[0]; $n = $n +5;});

my $result = $array[1](2); ---------> works and does not need &{$array[1]}(2)
print "$result \n"; 

【问题讨论】:

  • 只要你有一个多层数据结构,就会在层之间假设取消引用箭头->。换句话说,$array[1](2)$array[1]->(2) 相同。
  • &$addref(5) 可以正常工作。

标签: perl reference anonymous-methods


【解决方案1】:

在函数调用中& 是可选的,但为什么在这种情况下不是。

在子例程中调用& 是可选的,但仅当您已经拥有子例程时才需要,而不是在您需要先取消引用它时。

取消引用的首选方法是-> 符号。

$subroutine_ref->(5); 
$hash_ref->{'key'};
$array_ref->[5];

当然是TIMTOWTDI,您可以使用键入的符号来取消引用而不是->

 &$subroutine_ref(5);  # same effect as $subroutine_ref->(5)

但我觉得这不太可读。


my $result = $array[1](2); # works and does not need &{$array[1]}(2)

如果这涉及多个层次,则部件之间的 -> 是隐含的和可选的。

$array[1](2); # shorthand for $array[1]->(2);

不过,您可能仍然需要第一个:如果您有一个数组引用而不是数组,那么您会这样做

$array_ref->[1](2);

【讨论】:

    【解决方案2】:

    问题是 Perl 必须对你的意思做出可靠的猜测。

    鉴于$add_ref的这个定义

    sub add { return $_[0]+5; };
    my $add_ref = \&add;
    

    调用子例程的“正确”方法是使用间接运算符->,它隐式取消引用其左操作数(类似于“胖逗号”=> 隐式引用其左操作数)。

    因此您可以将取消引用显式编写为

    &$add_ref(5)
    

    或隐含地使用

    $add_ref->(5)
    

    Perl 总是非常努力地通过你写的东西来理解你的意思意思,所以我确信可以解决你的陈述

    $result = $add_ref(5)  # Syntax error
    

    因为间接子程序调用会导致歧义问题。

    你的第二个陈述更清楚

    $result = {$add_ref}(5)  # Syntax error
    

    这是一个语法错误,因为裸块不能返回值。 (实际上,您正在声明一个带有单个键且没有值的匿名哈希,然后尝试调用它。)如果您使用do 和间接运算符,那么一切都很好。像这样

    $result = do{$add_ref}->(5)
    

    但我不会推荐它。或者您可以将块放在上下文中,就像您在下一个示例中所做的那样,然后编写

    $result = &{$add_ref}(5)
    

    由于首先发生取消引用,因此与

    相同
    $result = &$add_ref(5)
    

    虽然 Perl 引用可能看起来令人困惑,但随着您习惯该语言,它会变得更加清晰。由于作者 Larry Wall 的语言学背景,它的工作原理非常像一种非常正式的自然语言。在每一种口语中,都有无穷无尽的“不规则”词,它们之所以这样发展,是因为使用它们的人觉得它最方便。没有其他“为什么”,但这就是为什么在 Perl 上花费不到几个月的程序员会很快谴责它晦涩难懂的原因。

    【讨论】:

    • 感谢@Borodin 详细回答了语法背后的想法!
    猜你喜欢
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2011-01-17
    • 2013-02-06
    • 2013-10-13
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多