2013-06-10 3 views
2

Как передать часть хеша в подпрограмму?Как передать часть хеша в подпрограмму?

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

ответ

2

Pass $list{$i} к подпрограмме,

use strict; 

check_something ($list{$i}); 

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

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

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

$ href {name} имеет значение null в подпрограмме. – shaun5

+2

'$ href -> {name}' not '$ href {name}' –

+0

@ shaun5, Это неверно. Попытка использования '$ href {name}' выдает ошибку времени компиляции. Вы должны использовать '$ href -> {name}' – ikegami

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

$ item {name} имеет значение null в подпрограмме. – shaun5

+2

+1 при использовании строгих/предупреждений! –

+0

@ shaun5, Это неправда. Попытка использовать '$ item {name}' выдает ошибку времени компиляции. Вы должны использовать '$ item -> {name}' – ikegami

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

Wow! Очевидно, что я делаю. У меня есть хеш, который называется %list, который содержит объекты виджетов! Моя подпрограмма 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 знает, какой check_something I должен работать.

  • И наконец, use strict; не работает.Прагма use strict; улавливает 90% ваших ошибок. Тем не менее, при создании этих сложных структур путем рубя их из сырого кода, вы можете в конечном итоге создать то же время ошибок, которые use strict; бы поймать, но не может:

Например:

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

Вы видите ошибку? Я использовал quantity в одном, но затем с ошибкой quanity в другом. Этот тип ошибки не будет обнаружен компилятором. Однако:

$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 поймает свою ошибку, потому что quanity это не просто ключ к опорному хэш, но это не существует подпрограмма.

Другие уже дали вам технически правильный ответ, но если вы регулярно используете сложные структуры данных, такие как хеши хэшей или хэшей списков или списки хешей, пришло время начать работу с объектами. Как только вы начнете использовать их, вы обнаружите, что сможете быстрее кодировать код с меньшим количеством разочарования и меньшим количеством логических проблем.