2012-05-22 15 views
6

Pregunta 1:¿Cómo puedo pasar una matriz a una función en Perl?

Quiero pasar una matriz a una función. Pero el argumento pasado se cambia en la función. ¿Se lo llama por valor?

Pregunta 2:

#my ($name, $num, @array)= @_; <=1) 
my $name = shift;    <=2) 
my $num = shift; 
my @array = shift; 

Caso 1 y 2 tiene salida diferente. ¿Por qué ocurrió?

#!/usr/bin/perl 
use strict; 

my @test1; 
push @test1, ['a', 1]; 
push @test1, ['b', 1]; 
push @test1, ['c', 1]; 
push @test1, ['d', 1]; 
push @test1, ['e', 1]; 

for (my $i=0; $i< scalar(@test1); $i++) { 
    print "out1: $test1[$i][0] $test1[$i][1]\n"; 
} 

test_func("test_func", 10, @test1); 

sub test_func { 
    #my ($name, $num, @array)= @_; <=1) 
    my $name = shift;    <=2) 
    my $num = shift; 
    my @array = shift; 

    print "$name\n"; 
    print "$num\n"; 

    for (my $i=0; $i< scalar(@test1); $i++) { 
     print "$array[$i][0] $array[$i][1]\n"; 
    } 

    for (my $i=0; $i< scalar(@test1); $i++) { 
     if ($array[$i][0] eq 'a') { 
      $array[$i][0] = 'z'; 
     } 
    } 
    for (my $i=0; $i< scalar(@test1); $i++) { 
     print "change: $array[$i][0] $array[$i][1]\n"; 
    } 
} 

for (my $i=0; $i< scalar(@test1); $i++) { 
    print "out2: $test1[$i][0] $test1[$i][1]\n"; 
} 
#

A continuación se muestra la salida de prueba.

out1: a 1 
out1: b 1 
out1: c 1 
out1: d 1 
out1: e 1 
test_func 
10 
a 1 
b 1 
c 1 
d 1 
e 1 
change: z 1 
change: b 1 
change: c 1 
change: d 1 
change: e 1 
out2: z 1 <= Why did it change? 
out2: b 1 
out2: c 1 
out2: d 1 
out2: e 1 

Respuesta

10
Quiero pasar una matriz a [...] una función que tiene una salida diferente. ¿Por qué ocurrió?

No se puede pasar una matriz a una función sub. Subs solo puede tomar una lista de escalares como argumentos.

test_func("test_func", 10, @test1); 

es lo mismo que

test_func("test_func", 10, $test1[0], $test1[1], $test1[2], $test1[3], $test1[4]); 

Usted está creando una nueva matriz en test_func cuando haces

my ($name, $num, @array) = @_; 

shift devuelve el primer elemento de @_, que es necesariamente un escalar. @_ es una matriz, y los elementos de las matrices son escalares. El equivalente sería

my $name = shift(@_); 
my $num = shift(@_); 
my @array = splice(@_); 

pasar una matriz a un sub, que normalmente se pasa una referencia a la misma.

test_func("test_func", 10, \@test1); 

my ($name, $num, $array) = @_; 

my $name = shift; 
my $num = shift; 
my $array = shift; 

say "@$array"; 

Pero el argumento pasado se cambia en la función. ¿Se lo llama por valor?

Perl nunca pasa por valor. Siempre pasa por referencia. Si cambia cualquier elemento de @_, cambiará el argumento correspondiente en la persona que llama.

$ perl -E'sub f { $_[0] = "def"; } my $x = "abc"; f($x); say $x;' 
def 

Pero ese no es el problema. No cambia ningún elemento de @_. Lo que está haciendo es cambiar la única matriz a la que hacen referencia $test[0] y $array[0].

Esto es lo que está haciendo:

my $ref1 = [ 'a', 1 ]; # aka $test1[0] 
my $ref2 = $ref1;  # aka $array[0] 
$ref2->[0] = 'z';  # Changes the single array (not $ref1 or $ref2). 

Es la abreviatura de

my @anon = ('a', 1); 
my $ref1 = \@anon;  # aka $test1[0] 
my $ref2 = $ref1;  # aka $array[0] 
$ref2->[0] = 'z';  # Changes @anon (not $ref1 or $ref2). 

Storable 's dclone se puede utilizar para hacer una "copia en profundidad" de una matriz.

my $ref1 = [ 'a', 1 ]; 
my $ref2 = dclone($ref1); # clones the reference, the array, 'a' and 1. 
$ref1->[0] = 'y';   # Changes the original array 
$ref2->[0] = 'z';   # Changes the new array 
+0

gracias por su amable explicación.Yo resuelvo mi problema difícil ^^ – user1395438

+0

si esta solución ha ayudado, marque la marca de verificación junto a él –

+0

... y si no, díganos lo que falta. – ikegami

Cuestiones relacionadas