2012-04-03 9 views
11

Ho un codice che non funziona nel modo in cui mi aspetto e apprezzerei un po 'di aiuto per capire come farlo funzionare come mi aspetto.Modifica dell'array nella subroutine

Mi piacerebbe utilizzare una subroutine per modificare un array di input. Ho pensato che se avessi passato un riferimento all'array, le eventuali modifiche apportate si sarebbero riflesse anche nella versione del chiamante. Ma a quanto pare non funziona in questo modo.


my @test_array = qw (zero one two three); 

shift_array(\@test_array); 
print "POST SUBROUTINE: $test_array[0]\n"; 

sub shift_array { 
    my @array = @{(shift)}; 
    shift @array; 
    print "AFTER SHIFT IN SUB: $array[0]\n"; 
} 

Questo stampa:

 
AFTER SHIFT IN SUB: one 
POST SUBROUTINE: zero 

mi aspettavo che la stampa one entrambe le volte.

Quindi la mia domanda è duplice:

1) Perché non è vero comportando il modo in cui penso che dovrebbe? Passare un riferimento a un array crea una copia dell'array?

2) Come si ottiene il comportamento che mi aspettavo? Come faccio a ottenere una subroutine per far scorrere uno o più elementi dalla parte anteriore della copia di un array di input del chiamante?

Grazie in anticipo per qualsiasi suggerimento che possiate offrire.

risposta

9

Perché my @array è un nuovo array a cui è stato assegnato l'array originale senza segno. È una copia

Invece fare questo:

sub shift_array { 
    my $array = shift; 
    shift(@$array); 
} 

Edit: Originariamente ho detto dereferencing crea il problema, ma utilizzando @$array è ancora dereferencing esso. Come ha sottolineato @mob, l'assegnazione della variabile è ciò che crea la nuova matrice invece di aggiornare il riferimento esistente.

+0

Wow. Questa è una sfumatura che non ho capito. Grazie! – BlairHippo

+1

@mob sei corretto. Modificare la mia risposta per chiarire – Cfreak

+2

nota che con perl 5.14+ puoi scrivere 'shift $ array' nel sub e il de-referencing avviene automagicamente. – mirod

0

Questo è uno dei (pochi) casi in cui i prototipi Perl sono utili.

#!/usr/bin/perl 

use strict; 
use warnings; 

# Prototype forces the first argument to be a reference to an array  
sub shift_array (\@) { 
    my $array = shift; 
    shift(@$array); 
    print "AFTER SHIFT IN SUB: @$array[0]\n"; 
} 

my @test_array = qw (zero one two three); 

shift_array(@test_array); 
print "POST SUBROUTINE: $test_array[0]\n"; 
0

io preferisco essere più coerente nell'uso di riferimenti ad array per minimizzare l'ambiguità:

#!/usr/bin/perl 
use strict; 
use warnings; 

my @test_array = qw (zero one two three); 

shift_array(\@test_array); 
print "POST SUBROUTINE: $test_array[0]\n"; 

sub shift_array { 
    my $ref = shift; 
    shift @$ref; 
    print "AFTER SHIFT IN SUB: ${$ref}[0]\n"; 
} 
Problemi correlati