【问题标题】:Perl: Return hash from subroutinePerl:从子例程返回哈希
【发布时间】:2014-07-02 04:21:50
【问题描述】:

我已经尝试了几个小时的例子,但我似乎无法掌握如何做我想做的事情。

我想从子例程返回一个哈希值,我认为引用是最好的选择。这是有点棘手的地方。我想引用像 $hash{$x} 这样的哈希。我仍然是 perl 的菜鸟:/

1.第一个问题,我使用的示例似乎表明使用 $hashTable{$login} 是可以的,我应该使用 %hashTable{$login} 还是无所谓?下面是代码:

sub authUser  {
    $LocalPath = "/root/UserData";
    open(DATAFILE, "< $LocalPath");
    while( $linebuf = <DATAFILE> ) {
        chomp($linebuf);
        my @arr = split(/:/, $linebuf);
        my $login = $arr[1];        # arr[1] contains the user login names
        my $hashTable{ $login } = "$arr[0]";        #$arr[0] is account number
    }
    close DATAFILE;
    return \$hashTable{ $login };
}

然后我想测试这些数据以查看是否存在登录,这是我的测试方法

# test login Dr. Brule which is present in UserData
my $test = "Dr. Brule";
my $authHash = &authUser();

if ( $authHash{ $test } )  {
    print "Match for user $test";
}
else  {
    print "No Match for user $test";
}

2.如果我的 $authHash 真的是 $authHash{ $something },我对此感到很困惑

编辑:经过一些阅读提示,仍在尝试但没有骰子,任何帮助将不胜感激


编辑 2:任何人都可以修改我的代码以便我更好地理解答案吗?很抱歉,我似乎根本无法让它工作,我已经尝试了几个小时,我真的很想知道正确的方法,我可以发布我的各种尝试,但我觉得这将是一种浪费的房地产。

【问题讨论】:

标签: arrays perl hash subroutine


【解决方案1】:

首先,正如 cmets 中提到的 mpapec,use strict; use warnings;。这将捕获最常见的错误,包括标记您在此处询问的大多数问题(并且通常会提供有关您应该做什么的提示)。

现在回答问题 1 和 2:

%hash 是一个整体的哈希值。完整的数据结构。

$hash{key} 是散列中的单个元素。

因此,\%hash 是对%hash 的引用,即整个哈希,这似乎是您在这种情况下打算返回的内容。 \$hash{key} 是对单个元素的引用。

第二个问题的棘手之处在于引用始终是标量,无论它们引用什么。

$hash_ref = \%hash

要从您引用的哈希中获取一个元素,您需要先取消引用它。这通常使用-&gt; 运算符完成,如下所示:

$hash_ref-&gt;{key}

请注意,当您从引用 ($hash_ref-&gt;{key}) 开始时使用 -&gt;,而不是从实际哈希 ($hash{key}) 开始时。

(作为问题 2 的附注,不要在子调用前加上 &amp; - 只需使用 authUser() 而不是 &amp;authUser()。在 Perl 5+ 中不再需要 &amp; 并且有旁注你通常不想要的效果,所以你不应该养成在不需要的地方使用它的习惯。)

对于第3题,如果你只检查一次,你也可以循环遍历数组并检查每个元素:

my $valid;
for my $username (@list_of_users) {
  if ($login eq $username) {
    $valid = 1;
    last; # end the loop since we found what we're looking for
  }
}

if ($valid) {
  print "Found valid username $login\n";
} else {
  print "Invalid user! $login does not exist!\n";
}

【讨论】:

  • 感谢您的帖子,我一直在阅读有关取消引用的内容,您能否详细说明“要从您引用的哈希中获取元素,您需要先取消引用它。这是通常使用 -> 运算符完成,例如:$hash_ref->{key}"。我决定在完全看中之前尝试使用参考,但是当我尝试从参考中填充任何数据时,我什么也没想到。
【解决方案2】:

需要明确的是,Perl 使用标量或它们的列表

$scalar = 1;
@list = ( $scalar, $scalar, $scalar );

列表的每个项目都可以通过索引访问,例如$list[1].
您还可以按名称访问项目。这种结构称为哈希:$hash{ name1 }

%hash = ( 'name1', $scalar, 'name2', $scalar, 'name3', $scalar )

但是,如您所见,这仍然是一个列表。注意它周围的“()”。
再说一次,列表中的每一项只能是一个标量

我没有在任何一本书中看到这一点,但$ 符号表示一个值,@ 表示值列表。

在此示例中,您有 一个值,因此您使用 $ 符号:

$scalar =  $hash{ name1 };
$scalar =  $list[ 1 ];

在下一个示例中,您有一个值列表,因此您使用“@”:

@list2 =  @list1;            # copy all items
@list2 =  @list[ 1, 3..5 ];  # copy four items with index 1,3,4,5
@list2 =  @hash{ 'name1', 'name3' }; #copy two items with index 'name1', 'name2'

Perl 有引用。这是一个强大的工具。

$ref = \$scalar;
$ref = \@list;
$ref = \%hash;

$ref 也是标量,因为它只有一个值。要访问此$ref 引用的基础数据,您应该使用dereference

$scalar = $$ref;
@list   = @$ref;
%hash   = %$ref;

但实际上,您并不想要整个列表或散列。你只想要其中的一些东西。为此,您可以使用-&gt;[] 告诉 Perl 你想访问一个列表元素,或者使用 {} 告诉 Perl 你想访问一个哈希元素:

$scalar = $ref->[ 1 ];
$scalar = $ref->{ name1 };

注意:您正在访问一个元素,因此您使用$ 符号。

如果您想要数组或散列中的元素列表,请使用@ 符号。例如:

@list =  @$ref[ 1, 3..5 ];
@list =  @$ref{ 'name1', 'name2' };

1st: $ref - 返回对结构的引用。 $ 表示您从变量 'ref' 中获得 一个
第二:@$ref - 你取消引用 $ref。 @ 表示您希望通过该引用访问 列表 项。
3rd-a:您从数组中获得 '1,3,4,5' 项(注意:[]
3rd-b:你从哈希中得到 'name1'、'name2' 项(注意:{}

但是当您获取对哈希或列表的引用并将此引用放入另一个哈希或数组时,我们可能会创建复杂的结构,例如哈希数组或哈希数组的哈希。例子:

@list = ( 1, 2, 3, 4, 5 );
%hash = ( 'a', 1, b => 2 );
@list2 = ( \@list, \%hash, 3, 'y' );
%hash2 = ( name1 => \@list2, d => 4 );
%hash2 = ( 'name1', \@list2, 'd', 4 );  #same. no any difference.
$href  = \%hash2;

=&gt; - 只需引用左操作数并在其后加上,

如果你想访问'hash2'的一个项:

$scalar =  $hash2{ name1 };
$scalar =  $href->{ name1 };

在取消引用后使用$href-&gt; 将意味着%hash2

如果您想访问两个或更多项“hash2”:

@list =  @hash2{ 'name1', 'd' };
@list =  @$href{ 'name1', 'd' };

在取消引用后使用@$href 将意味着%hash2

详细说明

$scalar =  $hash2{ name1 }; # <--- What does this mean???

$hash2 表示我们访问 %hash2 的 一个 项。这是对列表的引用:

$list_ref =  $hash2{ name1 };
$scalar   =  $list_ref->[ 1 ]; # <--- what we get here???

$list_ref 表示我们访问一个项。 -&gt;[ 表示我们访问该列表。因为$list_ref 指的是@list2,所以我们访问\%hash。我们可以一步完成:

$scalar =  $hash2{ name1 }->[ 1 ];

当您将文本“$list_ref”替换为“$hash2{ name1 }”时,您可能会想到这里

我们说[ 1 ] 指的是%hash。因此,要访问该哈希的 一个 项,我们再次使用 $

$hash_ref  =  $hash2{ name1 }->[ 1 ];
$scalar    =  $hash_ref->{ b };

$hash_ref 表示我们访问一个项。 -&gt;{ 表示我们访问哈希。因为$hash_ref 指的是%hash,所以我们访问2。我们可以一步完成:

$scalar =  $hash2{ name1 }->[ 1 ]->{ b };

当您将文本 '$hash_ref' 替换为 '$hash2{ name1 }->[ 1 ]' 时,您可能会再次想到这里。但是hash2 这里是%hash2$href 呢?请记住这个例子:

$scalar =  $hash2{ name1 };
$scalar =  $href->{ name1 };

您可能会注意到,如果您通过 ref 访问该项目,您只需添加 -&gt;。比较:

@l = ( 1, 2, 3, 4 );
$scalar = $l[ 1 ];    # to access to second item of @l list
$hr = \@l;
$scalar = $hl->[ 1 ]; # to access to second item of @l list

%h = @l;
$scalar =  $h{ 1 }; 
$hr =  \%h;
$scalar =  $hr->{ 1 };

-&gt; 之后的括号类型将是 [ 用于数组或 { 用于哈希项。

$href 呢?

$scalar =  $hash2{ name1 }->[ 1 ]->{ b };
$scalar =  $href->{ name1 }->[ 1 ]->{ b };

在第一次取消引用之后,我们不需要-&gt;

$scalar =  $hash2{ name1 }[ 1 ]{ b };
                 ^-- first dereference
$scalar =  $href->{ name1 }[ 1 ]{ b };
                ^--first dereference

回到您的问题:在 Perl 中,您可以将值的 LIST 传递给 subs 并返回一个 LIST

sub test {
    return @_;
}

在这里我们返回所有我们得到的物品。

return \%hash;  # fn()->{ name1 }; # actually all these is list of one item
return \@list;  # fn()->[ 1 ]; # so we may write: (fn())[0]->[ 1 ];
return $scalar; # fn(); # here also list of one item
return ( $scalar, \%hash, \@list ); 
    (fn())[ 0 ]; 
    (fn())[ 1 ]->{ name1 };
    (fn())[ 2 ]->[ 1 ];

使用 $hashTable{$login} 可以,我应该使用 %hashTable{$login} 还是没关系?

不。您应该使用 $ 访问来自%hashTable一个 项。 $hashTable{$login} 是对的。
如果你想提取 两个 登录,你应该使用 @

@list =  @hashTable{ 'login1', 'login2' };
# or
$l1 = 'login1';
$l2 = 'login2';
@list =  @hashTable{ $l1, $l2 };

返回 \$hashTable{ $login };

错了。您从哈希中返回 一个 项。所以 return $hashTable{ $login } 是对的。

2.如果我的 $authHash 真的是 $authHash{ $something },我对此感到很困惑

我想你的%hashTable 是一个由 $login 键入的哈希列表。像这样:

$login1 = { name => 'Vasiliy',   pass => 'secret' }  # ref to hash
%login2 = ( name => 'Petrovich', pass => '^&UDHJ' ); # just a hash
%hashTable = (
    vasya => $login1,  # items are always refs!!!
    piter => \%login2, # items are always refs!!!
)

所以authUser sub 会返回一个引用:

my $authHash = authUser( 'vasya' ); # & is not required at all

由于$authHash,如果引用是一个哈希,你应该使用-&gt;

if( $authHash->{ pass } eq $password ) {
...
}

但是,如果您的 authUser 是一个解析配置文件并返回所有用户,您应该将其重命名为 loadUsers 并返回一个 reference 到哈希: 子加载用户{ …… 返回\%哈希表; }

my $usersDB =  loadUsers;

if( $usersDB->{ $login }->{ pass } eq $password ) {
     print 'You have granged access';
}
else { ... }

编辑 2:任何人都可以修改我的代码以便我更好地理解答案吗?

不。阅读我的教程。要了解如何编写代码,您应该自己动手。

作为建议

当你是新手时:

  • 总是使用 hashref 和 listref。
  • 总是使用-&gt; 访问项目。
  • 总是使用 $ 印记作为第一个字符。

.

$list = [ 1, 2, 3 ];
$hash = { a => 1, b => 2 };
$list->[ 2 ];
$hash->{ b };

当您访问整个数组或散列时例外:

@l = @$list;
%h = %$hash;
@l = keys %$hash;
@l = values %$hash;

【讨论】:

    【解决方案3】:

    你可能不想这样做:

    return \$hashTable{ $login };
    

    您正在返回一个指向您的哈希的引用(指针)。 试试吧

    return $hashTable{$login} 
    

    这将返回帐号。

    或者如果你真的想要一个有一堆人的哈希,那么

    返回\$哈希表

    很好(不要添加 {$login} 部分),但另一方面你需要 取消引用。

    例如:

       my $p = authUser()
       if ($p->{'Dr. Brule'})
       ...
    

    注意里面的->。它取消引用您传回的指针。

    【讨论】:

      猜你喜欢
      • 2013-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-06
      • 1970-01-01
      • 2015-11-04
      • 2015-01-19
      • 1970-01-01
      相关资源
      最近更新 更多