Question:
I have a function that returns two 'arrays', but I was having difficulty assigning these results to two 'array' variables.
my (@A, @N) = volver_dos_arrays;
dd @A; # muestra lo que está dentro de @A (dd = "data dumper")
dd @N;
sub volver_dos_arrays
{
my @alfa = <A B C>;
my @num = 1, 2, 3;
return @alfa, @num;
}
It results in the following: where we can see that the first 'array' saved the two 'arrays' that the function returned:
Array @A = [["A", "B", "C"], [1, 2, 3]]
Array @N = []
But, I wanted it to be like this:
Array @A = ["A", "B", "C"]
Array @N = [1, 2, 3]
I know the following works, but I don't like saving an 'array' to a 'scalar'. I don't want to change the sigil of @A
or @N
.
my ($A, $N) = volver_dos_arrays;
dd $A;
dd $N;
sub volver_dos_arrays
{
my @alpha = <A B C>;
my @num = 1, 2, 3;
return @alpha, @num;
}
How can I do this without changing the sigils?
I learned how to do it, but I still ask the question because it stumped me for a couple of hours. I make an answer if no one gives an answer similar to what I found out.
Answer:
Indeed as the other answer has said, with arrays, you have to use a binding assignment:
my (@A, @N) := volver_dos_arrays();
We can see why using other values:
sub volver-valores { 1,2,3,4 }
my ($a,$b) = volver-valores();
say $a; # 1
say $b; # 2
When we use a list assignment (with my ( … )
), each variable consumes values according to its stealth, and unneeded values are discarded. Thus, $a
, being scalar, consumes one value ( 1
), and $b
also consumes another. The others ( 3
, 4
) are discarded.
If we have an array with its corresponding sigil, the last values are not discarded, but the array consumes them as elements:
sub volver-valores { 1,2,3,4 }
my ($a,@b) = volver-valores();
say $a; # 1
say @b; # 2 3 4
Now, I imagine, you can see the problem. If the first element of the assignment is an array, it will already consume all the values, leaving the second to have the default value (empty, in the case of arrays):
sub volver-valores { 1,2,3,4 }
my (@a,@b) = volver-valores();
say @a; # 1 2 3 4
say @b; # [vacío]
When we use binding assignment, arrays do not consume elements to form the array. We can no longer use the old sub, because if we use it:
sub volver-valores { 1,2,3,4 }
my (@a,@b) := volver-valores();
# Type check failed in binding to parameter '@a'; expected Positional but got Int (1)
We see that you are trying to make the array 1
. But an array can't be an integer (although it can contain integers), so it fails. Now we change the sub:
sub volver-valores { (1,2,3),<a b c> }
my (@a,@b) := volver-valores();
say @a; # 1 2 3
say @b; # a b c
But beware! the type of @a
and @b
is not Array, but List. This is because in the list binding assignment, we say "let @a be the first value" (and not "let @a
be based on the first value). If we used a normal assignment, the difference is already clear:
sub volver-valores { (1,2,3),<a b c> }
my (@a,@b) = volver-valores();
say @a; # [1 2 3 a b c] (un arreglo de dos elementos de tipo List)
say @b; # [vacío]
Now, we have said "let @a
be made up of the following values", and these two values are a list 1,2,3
and another list a,b,c
.