Perl:将两个哈希传递给sub

时间:2016-10-14 10:00:41

标签: perl hash parameter-passing

下面是一个小子,通过传递两个包含x和y坐标的哈希来计算两点之间的距离。我在{"附近发现了#34;语法错误在调用sub的行上发生致命错误。刚刚开始使用Perl,并不完全确定我在做什么。如何将两个哈希值传递给sub以返回值?尝试this但没有取得多大成功,也不确定我需要做些什么(希望可以参考外部链接)。

%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);

3 个答案:

答案 0 :(得分:3)

首先,您应该使用

启动每个文件
use strict;
use warnings;

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

此部分基本上很好,但在use strict下,Perl会抱怨%dot1%dot2未声明(并且没有strict它们将隐含全局,这通常是不是你想要的):

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

将其更改为

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

电话

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

有同样的问题:它应该是

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

它的作用是将对%dot1%dot2的引用传递给子dist

    my (%hash1) = @_[0];

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

但在任何一种情况下,将单个元素分配给哈希都没有意义。 Perl会将其解释为键并将相应的值设置为$_[0]。您的调用作为第一个参数传递undef,因此\%dot1是对哈希的引用。通过将其用作哈希键,Perl会将其转换为字符串,产生类似$_[0]的内容。

此时您的选择是在此处取消引用引用并复制:

"HASH(0x0075ADD40)"

每次需要访问哈希值时,请保留引用并取消引用它:

    my %hash1 = %{ $_[0] };   # effectively performs %hash1 = %dot1
    my $hashref1 = $_[0];     # $hashref1->{foo} accesses $dot1{foo} directly

这里有一些问题。首先,您不需要(隐式全局)变量 $dist = ((@_[0]{'x'}-@_[1]{'x'})**2 + (@_[0]{'y'}-@_[1]{'y'})**2)**0.5; 。您只想从sub返回一个值,可以使用$dist来完成。然后,如上所述,return@_[0]应分别为@_[1]$_[0]。修复我们得到的

$_[1]

确实有效( return (($_[0]{'x'} - $_[1]{'x'}) ** 2 + ($_[0]{'y'} - $_[1]{'y'}) ** 2) ** 0.5; $_[0]{'x'}的语法糖,即此表达式取消引用存储在$_[0]->{'x'}中的哈希引用,以达到$_[0]的{​​{1}}键}})。

但我们根本没有使用我们刚创建的变量。根据您要采用的方式,您应该将'x'替换为%dot1$_[0]{foo}(以及$hash1{foo}$hashref1->{foo} / {{1} })。

最后,我们可以使用$_[1]而不是%hash2

以下是我写的方式:

$hashref2

答案 1 :(得分:2)

这里有很多问题,我很害怕。

首先,您需要在代码中添加use strictuse warnings。这将指出许多错误。主要是您使用@array[index]但应该使用$array[index]的地方。您也没有声明任何变量。

修复所有这些代码给了我这个代码:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

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

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

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


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

say $D;

这仍然无法奏效。我明白了:

$ perl twohash
Reference found where even-sized list expected at twohash line 11.
Reference found where even-sized list expected at twohash line 12.
2.82842712474619

错误是您将传递给dist()的两个参数分配的地方。

my (%hash1) = $_[0];
my (%hash2) = $_[1];

您正在传递对哈希的引用,而不是哈希本身(并且您正确地执行此操作),但这意味着您在子例程中获得了标量,而不是哈希。所以这些行必须是:

my ($hash1) = $_[0];
my ($hash2) = $_[1];

进行这些更改后,代码现在可以运行并提供结果" 2.82842712474619"。

我只是在你的代码中指出一个更奇怪的东西 - 你将函数的参数分配给两个词法变量($hash1$hash2),然后你忽略那些变量而不是直接转到@_获取此数据。我希望你真的想要:

my $dist = (($hash1->{'x'}-$hash2->{'x'})**2 + ($hash1->{'y'}-$hash2->{'y'})**2)**0.5;

注意,我已将$_[0]{'x'}更改为$hash1->{'x'},因为您引用了哈希。

总而言之,这段代码有点乱,我建议你回到你从Perl那里学到的任何书的最早章节。

答案 2 :(得分:-1)

请你试试这个:

use Data::Dumper;

my %dot1 = ('x'=>5, 'y'=>6);
my %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);

print $D;