如何将部分哈希传递给子例程?

时间:2013-06-10 20:00:54

标签: perl

如何将部分哈希传递给子程序?

%list = ( 1 => {name => 'first', quantity => 2},
  2 => {name => 'second', quantity => 3});
$i = 2;

#doesn't work....
check_something ( \%{list}{$i} );
sub check_something {
   %local = @_;
}

#doesn't work....
check_something ( \%list, $i );
sub check_something {
   my ($ref, $item) = @_
   %local = %{$ref}{$item};
}

3 个答案:

答案 0 :(得分:2)

$list{$i}传递给子程序,

use strict;

check_something ( $list{$i} );

sub check_something {
   my ($href) = @_;

   # $href->{name}, $href->{quantity}

   my %hash = %$href;
   # $hash{name}, $hash{quantity}
}

答案 1 :(得分:2)

这有效:

use strict;
use warnings;


my %list = ( 
    1 => {name => 'first', quantity => 2},
    2 => {name => 'second', quantity => 3}
);
my $i = 2;

check_something ( $list{$i} );

sub check_something {
   my $item = shift;
   #...
}

答案 2 :(得分:0)

每当你将超过标量数据的东西存储到Perl变量中时,你应该开始考虑面向对象的Perl。

查看Perl Object Oriented Tutorial

我要去你所有的面向对象:

#! /usr/bin/env perl

use strict;
use warnings;

my %list;

my $list{1} = Widget->new("first", 2);
my $list{2} = Widget->new("second", 3);
my $i = "2";
check_something( $list{$i} );

哇!很明显我在做什么。我有一个名为%list的哈希,其中包含Widgets的对象!我的check_somthing子例程正在获取一个Widget对象。它应该是$list{$i}作为参数。

但是Widgets看起来像什么:

package Widget;
sub new {
    my $class    = shift;
    my $self     = shift;
    my $name     = shift;
    my $quantity = shift;

    my $self = {};
    bless $self, $class;
    $self->Name($name) if defined $name;
    $self->Quantity($quantity) if defined $quantity;
    return $self;
}

sub name {
    my $self = shift;
    my $name = shift;

    if ( defined $name ) {
       $self->{name} = $name;
    }
    return $self->{name};
}

sub Quantity {
    my $self    = shift;
    my $quanity = shift;

    if ( defined $quanity ) {
       $self->{quantity} = $quantity;
    }
    return $self->{quantity};
}

这很简单。通过使用对象而不是哈希的哈希,我简化了我的逻辑。很容易看出我想传递给我的子程序的是一个Widget对象。实际上,check_somthing子例程可能是另一种方法:

sub check_something {
    my $widget = shift;

    my $name = $widget->Name;
    my $quanity = $widget->Quantity;

    # Here be dragons...

    return ???
}

现在,我的代码如下所示:

#! /usr/bin/env perl

use strict;
use warnings;

my %list;

my $list{1} = Widget->new("first", 2);
my $list{2} = Widget->new("second", 3);
my $i = "2";

$list{$i}->check_something;

请注意,这会改善您的代码:

  • 首先它清理你的逻辑。你没有传递一个列表的哈希或哈希或一些难以理解的结构,你可能浪费了两到三个小时试图在你放弃之前弄清楚并在这里问一个问题。 (没有犯罪。我去过那里,自己也做过)。相反,你传递的是一个易于理解的对象
  • 其次,它确保您的check_something子例程只能由窗口小部件使用。如果您尝试将非Widget对象传递给check_something,它将失败。更好的是,我可以使用另一个名为Wooble的对象,它有自己的check_something子例程,而Perl会弄明白我正在检查的内容。

例如:

my $widget = Widget->new("first", 2);
my $wooble = Wooble->new(1, "slam");

$widget->check_something;
$wooble->check_something;

Widgets和Woobles有自己的check_something方法和Perl,因为它知道哪个对象是 Widget ,哪个对象是 Wooble 知道哪个{ {1}}我应该跑。

  • 最后,check_something不再被打破。 use strict; pragma会捕获90%的错误。但是,当您通过将它们从原始代码中删除来创建这些复杂结构时,您最终可能会创建use strict;将捕获但不能捕获的错误的相同时间:

例如:

use strict;

你看到错误吗?我在一个中使用了%list = ( 1 => {name => 'first', quantity => 2}, 2 => {name => 'second', quanity => 3} ); ,但在另一个中使用了quantity拼写错误。编译器不会捕获此类错误。但是:

quanity

现在,Perl编译器将捕获我的错误,因为$list{1} = Widget->new; $list{1}->name('first'); $list{1}->quantity(2); $list{2} = Widget->new; $list{2}->name('second'); $list{2}->quanity(3); #Compiler Error! 不仅仅是哈希引用的关键,而且是一个不存在的子例程。

其他人已经为您提供了技术上正确的答案,但如果您经常使用复杂的数据结构,例如散列哈希值或列表哈希值或哈希列表,那么就该开始使用对象了。一旦你习惯了它们,你会发现你可以更快地编写代码,减少挫败感和减少逻辑问题。