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

Pregunta 1:

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

Pregunta 2:

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

Los casos 1 y 2 tienen una 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

preguntado el 22 de mayo de 12 a las 17:05

1 Respuestas

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

No puede pasar una matriz a un función sub. Los subs solo pueden tomar una lista de escalares como argumentos.

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

es el mismo que

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

Estás creando una nueva matriz en test_func Cuando tu lo hagas

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

shift devuelve el primer elemento de @_, que es necesariamente un escalar. @_ es un arreglo, y los elementos de los arreglos son escalares. el equivalente seria

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

Para pasar una matriz a un sub, normalmente se le pasaría una referencia.

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 llama por valor?

Perl nunca pasa por valor. Siempre pasa por referencia. Si cambia algún 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 cambias ningún elemento de @_. Lo que está haciendo es cambiar la matriz única a la que hacen referencia ambos $test[0] y $array[0].

Esto es lo que estas 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 corto para

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).

Almacenable's dclone se puede usar para hacer una "copia profunda" 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

respondido 15 nov., 15:21

gracias por tu amable explicación. resuelvo mi problema difícil ^^ - user1395438

si esta solución ha ayudado, marque la marca de verificación junto a ella - Joel Berger

...y si no, cuéntanos qué falta. - Ikegami

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.