¿Cómo podemos enviar una estructura de datos compleja usando los mecanismos introducidos en las secciones anteriores? Supongamos, por ejemplo, que deseamos comunicar una referencia a un hash cuyos valores son a su vez referencias a arrays, etc.
El módulo Data::Dumper nos da una solución parcial al problema.
nereida:/tmp> perl -MData::Dumper -wde 0 main::(-e:1): 0 DB<1> $a = [[1,2],[3,4]] DB<2> p Dumper $a $VAR1 = [[ 1,2],[3,4]]; # Aparece $VAR1 = DB<3> $Data::Dumper::Terse = 1 DB<4> p Dumper $a [[1,2],[3,4]] # Eliminamos $VAR1 =
La representación por defecto de Data::Dumper
da lugar a problemas con las variables que se autoreferencian:
DB<26> $h = { name => 'juan' }; $m = { name => 'pedro' }
DB<27> $h->{hermano} = $m; $m->{hermano} = $h
DB<28> p Dumper $h
$VAR1 = {'hermano' => {'hermano' => $VAR1,'name' => 'pedro'},'name' => 'juan'};
DB<30> use strict; eval {$VAR1 = { \
'hermano' => {'hermano' => $VAR1,'name' => 'pedro'},'name' => 'juan'}\
}
Variable "$VAR1" is not imported
La solución está en establecer la variable Data::Dumper::Purity a cierto:
DB<31> $Data::Dumper::Purity=1
DB<32> p Dumper $h
$VAR1 = {'hermano' => {'hermano' => {},'name' => 'pedro'},'name' => 'juan'};
$VAR1->{'hermano'}{'hermano'} = $VAR1;
El siguiente ejemplo muestra como implantar RPC entre procesos
usando Data::Dumper:
lhp@nereida:~/Lperl/src/cookbook/ch16$ cat -n sendref.pl
1 #!/usr/bin/perl -w
2 use strict;
3 use Data::Dumper;
4 use IO::Pipe;
5 $| = 1;
6
7 my $FROM_CHILD = IO::Pipe->new;
8 my $FROM_FATHER = IO::Pipe->new;
9
10 my $pid;
11
12 if ($pid = fork) { # Father
13 die "cannot fork: $!" unless defined $pid;
14
15 $FROM_FATHER->writer;
16 $FROM_CHILD->reader;
17
18 my $x = $FROM_CHILD->receive;
19
20 @{$x->{vector}} = map { $_*$_ } @{$x->{vector}};
21
22 $FROM_FATHER->send($x);
23
24 print "Father:\n",Dumper($x);
25
26 close $FROM_CHILD;
27 close $FROM_CHILD;
28 waitpid($pid,0);
29
30 } else { # Child
31 $FROM_FATHER->reader;
32 $FROM_CHILD->writer;
33
34 my $x = { angle => atan2(1, 1), vector => [ 1..10] };
35 $FROM_CHILD->send($x);
36
37 $x = $FROM_FATHER->receive;
38
39 print "Child:\n",Dumper($x);
40
41 close $FROM_CHILD;
42 close $FROM_CHILD;
43 exit;
44 }
45
46 package IO::Pipe::End;
47 use Data::Dumper;
48 use strict;
49
50 sub receive {
51 my $channel = shift;
52
53 my $line;
54 sysread($channel, $line, 1024);
55 chomp($line);
56 return eval($line);
57 }
58
59 sub send {
60 my $channel = shift;
61 my $arg = shift || die "send error: expected a ref\n";
62
63 local $Data::Dumper::Indent = 0;
64 local $Data::Dumper::Terse = 1;
65 local $Data::Dumper::Purity = 1;
66 syswrite($channel, Dumper($arg)."\n");
67 }
68
69 1;
Al ejecutar el programa anterior obtenemos la salida:
lhp@nereida:~/Lperl/src/cookbook/ch16$ sendref.pl
Father:
$VAR1 = {
'angle' => '0.785398163397448',
'vector' => [
1,
4,
9,
16,
25,
36,
49,
64,
81,
100
]
};
Child:
$VAR1 = {
'angle' => '0.785398163397448',
'vector' => [
1,
4,
9,
16,
25,
36,
49,
64,
81,
100
]
};
