解释
是的。这种语法对于 Perl 来说是正确且惯用的。让我们剖析你的函数调用的所有部分——很可能你已经知道部分解释。
准备:你的输入数据
@array = (“0A0”, “005”, “001”, “004”, “0BC”, “004”, “002”, “001”);
@ranges = ();
# \@array and \@ranges are now normal scalar references.
我希望你理解数组引用的概念。如果没有,请阅读perlreftut或perllol。实际上,这不会影响您所询问的调用语法。顺便说一句,您可能还写过:
$array_ref=[“0A0”, “005”, “001”, “004”, “0BC”, “004”, “002”, “001”];
$range_ref=[];
$numRanges = buildRanges(VALUES => $array_ref, REF_RANGES=> $range_ref);
函数调用
在 Perl 中,箭头运算符 => 就像一个普通的逗号一样工作(我们稍后会讨论一个小的副作用)。以下调用完全相同:
$numRanges = buildRanges(VALUES => $array_ref, REF_RANGES => $range_ref);
$numRanges = buildRanges("VALUES", $array_ref, "REF_RANGES", $range_ref);
因此,您只需使用四个参数调用函数 buildRanges:两个常量字符串和两个数组引用。您注意到单词 VALUES 已更改为常量字符串“VALUE”;这同样适用于单词 REF_RANGES。这是一个特殊的规则:在箭头 => 之前和大括号 {} 内,普通标识符被默默地转换为字符串。我们在下面再次看到这一点。但是像 $a => $b 这样的其他表达式保持原样,这里不会发生到字符串的静默转换。
你可能会问为什么 Perl 会这样做?这是语法糖: => 运算符没有任何事情你不能轻易做到。但是对于有经验的 perl 程序员来说,格式 KEY => $value 看起来比 "KEY", $value 更清晰。
函数定义
函数 buildRanges 的定义可能如下所示(我们在解释中使用它):
sub buidRanges { my(%info)=@_;
my $values = $info{VALUES};
my $ref_ranges= $info{REF_RANGES};
my $special_feature = $info{SPECIAL_FEATURE}; # explained below
if($special_feature) { ... return special_result; }
... process $values and $ref_ranges ... return $numRanges.
}
对于您的输入数据,以下四行中的每一行都具有相同的效果:
my(%info)=@_; # the actual code
my(%info)=(VALUES => \@array, REF_RANGES=> \@ranges ); # what this does
my %info; $info{"VALUES"}=\@array; $info{"REF_RANGES"}=\@ranges;
my %info; $info{ VALUES }=\@array; $info{ REF_RANGES }=\@ranges;
基本上,输入数据被转换为允许访问每个参数的散列。函数调用中的常量字符串成为哈希键。
选择您理解的一行并将其与其他行进行比较:它们做同样的事情。查看perldsc以获得更多解释。
注意 @_ 是输入参数的数组,在我们的例子中
@_ = ( VALUES => \@array, REF_RANGES=> \@ranges);
@_ = ("VALUES", \@array,"REF_RANGES", \@ranges); # without syntactic sugar
您可能已经注意到 $info{VALUES} 等价于 $info{"VALUES"} —— 同样,这是语法糖,如上所述。
在我们假设的实现中,我们将输入数据从散列中提取出来:
my $values = $info{VALUES}; # i.e: my $value = \@array;
my $ref_ranges = $info{REF_RANGES}; # i.e: my $ref_renges = \@ranges;
现在,我们的函数实现可以处理输入数据。
为什么我们这样做不简单?--- 命名参数
到目前为止,我们可以更简单地实现类似的效果:
$numRanges = buildRanges($array_ref, $range_ref); # simpler function call
sub buidRanges { my($values, $ref_ranges)=@_;
... process $values and $ref_ranges ... return $numRanges.
}
这很可能是您已经很好理解的编程风格。
那么:为什么让一些 Perl 程序员更复杂(也更慢)?答案是:它更灵活,而且更能自我记录。
为了更清楚地说明这一点,我在我们的函数定义中添加了一个 SPECIAL_FEATURE。现在,该函数也可以这样调用:
$numRanges = buildRanges(VALUES => \@array, SPECIAL_FEATURE=> "infinite ranges");
实现的函数可以判断请求了 SPECIAL_FEATURE 并且未提供 REF_RANGES。
在一些高级函数中,您有很多有时(但并非总是)有用的额外特性,因此让调用者决定使用哪些特性以及不使用哪些特性是很有意义的。在这里,命名参数就派上用场了。
当然,我不能告诉你 buildRanges 函数识别了哪些特殊功能
——你需要查看它的实现或询问告诉你使用它的人。作为一般约定,也有可能某些项目中的所有高级函数都使用这种调用样式,即使其中一些没有提供太多特殊功能。