Perl 如何将散列的一部分传递给子例程?

Perl 如何将散列的一部分传递给子例程?,perl,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.... chec

如何将散列的一部分传递给子例程

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

$list{$i}
传递给子例程

use strict;

check_something ( $list{$i} );

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

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

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

$list{$i}
传递给子例程

use strict;

check_something ( $list{$i} );

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

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

   my %hash = %$href;
   # $hash{name}, $hash{quantity}
}
这项工作:

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;
   #...
}
这项工作:

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;
   #...
}

无论何时,在将标量数据以外的数据存储到Perl变量中时,都应该开始考虑面向对象的Perl

请看下面的图片

我将在您的网站上介绍所有面向对象的内容:

#! /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
的散列,其中包含小部件的对象!我的
检查\u something
子例程正在获取一个小部件对象。它应该是
$list{$i}
作为参数

但是小部件看起来像什么:

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};
}
这很简单。通过使用对象而不是散列中的散列,我简化了我的逻辑。很容易看出,我想要传递给我的子程序的是一个小部件对象。实际上,
check\u something
子例程可能是另一种方法:

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\u something
    子例程只能由小部件使用。如果尝试将非小部件对象传递给
    check\u something
    ,它将失败。甚至更好的是,我可以有另一个名为
    Wooble
    的对象,它有自己的
    check\u something
    子例程,Perl将知道我真正在检查什么
例如:

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

$widget->check_something;
$wooble->check_something;
%list = (
    1 => {name => 'first', quantity => 2},
    2 => {name => 'second', quanity => 3}
);
Widget和Wooble有自己的
check\u something
方法和Perl,因为它知道哪个对象是Widget,哪个对象是Wooble,知道我应该运行哪个
check\u something

  • 最后,
    严格使用不再被破坏。
    使用严格杂注捕获90%的错误。但是,当您通过从原始代码中删除这些复杂结构来创建这些复杂结构时,您最终可能会创建与
    使用strict相同的错误时间将捕获但无法:
例如:

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

$widget->check_something;
$wooble->check_something;
%list = (
    1 => {name => 'first', quantity => 2},
    2 => {name => 'second', quanity => 3}
);
你看到错误了吗?我在其中一个中使用了
quantity
,但在另一个中拼写错误了
quantity
。编译器不会捕获这种类型的错误。然而:

$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!
现在,Perl编译器将捕获我的错误,因为
quantity
不仅仅是散列引用的键,而是一个不存在的子例程


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

每当你在Perl变量中存储的不仅仅是标量数据时,你应该开始考虑面向对象的Perl

请看下面的图片

我将在您的网站上介绍所有面向对象的内容:

#! /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
的散列,其中包含小部件的对象!我的
检查\u something
子例程正在获取一个小部件对象。它应该是
$list{$i}
作为参数

但是小部件看起来像什么:

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};
}
这很简单。通过使用对象而不是散列中的散列,我简化了我的逻辑。很容易看出,我想要传递给我的子程序的是一个小部件对象。实际上,
check\u something
子例程可能是另一种方法:

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\u something
    子例程只能由小部件使用。如果尝试将非小部件对象传递给
    check\u something
    ,它将失败。甚至更好的是,我可以有另一个名为
    Wooble
    的对象,它有自己的
    check\u something
    子例程,Perl将知道我真正在检查什么
例如:

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

$widget->check_something;
$wooble->check_something;
%list = (
    1 => {name => 'first', quantity => 2},
    2 => {name => 'second', quanity => 3}
);
Widget和Wooble有自己的
check\u something
方法和Perl,因为它知道哪个对象是Widget,哪个对象是Wooble,知道我应该运行哪个
check\u something

  • 最后,
    严格使用不再被破坏。
    使用严格杂注捕获90%的错误。但是,当您通过从原始代码中删除这些复杂结构来创建这些复杂结构时,您最终可能会创建与
    使用strict相同的错误时间将捕获但无法:
例如:

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

$widget->check_something;
$wooble->check_something;
%list = (
    1 => {name => 'first', quantity => 2},
    2 => {name => 'second', quanity => 3}
);
你看到错误了吗?我在其中一个中使用了
quantity
,但在另一个中拼写错误了
quantity
。编译器不会捕获这种类型的错误。然而:

$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!
现在,Perl编译器将捕获我的错误,因为
quantity
不仅仅是散列引用的键,而是一个不存在的子例程


其他人已经给了您技术上正确的答案,但是如果您经常使用复杂的数据结构,如哈希表或列表哈希表,那么是时候开始使用对象了。一旦你习惯了它们,你会发现你可以用更少的挫折感和更少的逻辑问题更快地编码。

$href{name}在子例程中为空。
$href->{name}
不是
$href{name}
@shaun5,这不是tr