Perl:将两个哈希值传递给 sub

use*_*084 1 perl hash parameter-passing

下面是一个小子程序,通过传递两个散列(每个散列包含 x 和 y 坐标)来计算两点之间的距离。我在调用子函数的行上收到“语法错误接近]{”致命错误。昨天刚开始使用 Perl,不太确定我在做什么。如何将两个哈希值传递给子函数以返回值?尝试但没有取得多大成功,并且不确定我需要做什么(希望可以参考外部链接)。

%dot1 = ('x'=>5, 'y'=>6);
%dot2 = ('x'=>7, 'y'=>8);

sub dist {
    my (%hash1) = @_[0];
    my (%hash2) = @_[1];

    $dist = ((@_[0]{'x'}-@_[1]{'x'})**2 + (@_[0]{'y'}-@_[1]{'y'})**2)**0.5;
}


$D = dist(\%dot1,\%dot2);
Run Code Online (Sandbox Code Playgroud)

mel*_*ene 5

首先也是最重要的,您应该以以下方式开始每个文件

use strict;
use warnings;
Run Code Online (Sandbox Code Playgroud)

这可以让 Perl 捕获代码中最明显的错误。


这部分大部分都很好,但是在use strictPerl 下会抱怨%dot1并且%dot2未声明(如果没有strict它们将隐式全局,这通常不是您想要的):

%dot1 = ('x'=>5, 'y'=>6);
%dot2 = ('x'=>7, 'y'=>8);
Run Code Online (Sandbox Code Playgroud)

将其更改为

my %dot1 = ('x'=>5, 'y'=>6);
my %dot2 = ('x'=>7, 'y'=>8);
Run Code Online (Sandbox Code Playgroud)

电话

$D = dist(\%dot1,\%dot2);
Run Code Online (Sandbox Code Playgroud)

有同样的问题: 应该是

my $D = dist(\%dot1,\%dot2);
Run Code Online (Sandbox Code Playgroud)

它的作用是将引用传递给sub%dot1和sub 。%dot2dist


    my (%hash1) = @_[0];
Run Code Online (Sandbox Code Playgroud)

这一行没有多大意义:是一个列表切片,返回与索引对应的@_[0]元素列表。换句话说,它是一个单元素切片,最好写为,直接访问单个元素。@_0$_[0]

但无论哪种情况,将单个元素分配给哈希都是没有意义的。Perl 会将其解释为键并将相应的值设置为undef。您的调用\%dot1作为第一个参数传递,$_[0]对哈希的引用也是如此。通过使用它作为散列键,Perl 会将其转换为字符串,产生类似"HASH(0x0075ADD40)".

此时您的选择是取消引用该引用并制作副本:

    my %hash1 = %{ $_[0] };   # effectively performs %hash1 = %dot1
Run Code Online (Sandbox Code Playgroud)

或者保留引用并在每次需要访问哈希时取消引用它:

    my $hashref1 = $_[0];     # $hashref1->{foo} accesses $dot1{foo} directly
Run Code Online (Sandbox Code Playgroud)
    $dist = ((@_[0]{'x'}-@_[1]{'x'})**2 + (@_[0]{'y'}-@_[1]{'y'})**2)**0.5;
Run Code Online (Sandbox Code Playgroud)

这里有几个问题。首先,您不需要(隐式全局)变量$dist。您只想从 sub 返回一个值,这可以通过return. 那么,如上所述,@_[0]@_[1]应该分别是$_[0]$_[1]。修复我们得到的

    return (($_[0]{'x'} - $_[1]{'x'}) ** 2 + ($_[0]{'y'} - $_[1]{'y'}) ** 2) ** 0.5;
Run Code Online (Sandbox Code Playgroud)

这确实有效($_[0]{'x'}是 的语法糖$_[0]->{'x'},即该表达式取消引用存储在中的哈希引用$_[0]以达到'x'的键%dot1)。

但我们根本没有使用刚刚创建的变量。根据您想要走的路,您应该替换$_[0]{foo}$hash1{foo}or $hashref1->{foo}(以及类似的$_[1]and %hash2/ $hashref2)。

最后,** 0.5我们可以使用sqrt.


我是这样写的:

use strict;
use warnings;

sub dist {
    my ($p1, $p2) = @_;
    return sqrt(($p1->{x} - $p2->{x}) ** 2 + ($p1->{y} - $p2->{y}) ** 2);
}

my %dot1 = (x => 5, y => 6);
my %dot2 = (x => 7, y => 8);

my $D = dist(\%dot1, \%dot2);

print "Result: $D\n";
Run Code Online (Sandbox Code Playgroud)