Re: how to let sub return hash of 2 sub?
by choroba (Cardinal) on May 27, 2015 at 14:53 UTC
|
To create a code or subroutine reference, just use sub without a name:
my $x = sub { print shift };
To call such a subroutine, use the ->() dereference:
$x->('Hello world!');
It's a bit unclear what exactly you need. The following sub returns a hash of two subs:
#! /usr/bin/perl
use warnings;
use strict;
sub two_subs {
return { first => sub { return 'First: ' . shift },
second => sub { return 'Second: ' . shift },
}
}
print two_subs()->{first}->('A'), ' ', two_subs()->{second}->('B'), "\
+n";
| [reply] [d/l] [select] |
|
|
...
sub two_subs
{
...
return
{ 'first' => \&ElseWhere::first
, 'second' => \&ElseWhere::second
} ;
}
# In ElseWhere
...
sub first { 'first(): ' . shift }
sub second { 'second(): ' . shift }
...
| [reply] [d/l] |
Re: how to let sub return hash of 2 sub?
by ikegami (Patriarch) on May 27, 2015 at 14:49 UTC
|
That line will work if you return a list of objects.
Say you want to create an object for each element of a hash, where name is the key of the element, and val is the value of the element.
sub parameter {
...
return map { NameValTuple->new( name => $_, val => $rv{$_} } keys(%
+rv);
}
If you instead returned a list of hashes, it would look like
print $_->{name}, ': ', $_->{val}, "\n" for $objA->parameter( 'a.x' );
To return a list of hashes, you'd use
sub parameter {
...
return map { +{ name => $_, val => $rv{$_} } } keys(%rv);
}
(The "+" might not be needed. You can remove it if you don't get an error without it.) | [reply] [d/l] [select] |
|
|
Thanks at first, dear Ikegami.
I see that I have to describe a little bit more, what I'm trying to do. But bag you pardon, please don't laugh too much about me, it's my fault.
I have written now a short file of code, which should describe nearly, what I want to do.
___ testpar.pl ___
#!/usr/bin/perl
use objectA;
my %myhash = (
'a.x' => 1,
'b.y' => 2,
'c.x' => 3,
);
my $objA = objectA->new();
$objA->map_query( \%myhash );
print $_->name, ': ', $_->val, "\n" for $objA->parameter( 'a.x' );
print $_->name, ': ', $_->val, "\n" for $objA->parameter( 'b.y' );
return;
___ objectA.pm ___
package objectA;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub map_query {
my $self = shift;
my $hash = shift;
map { $self->{ values }->{ $_ } = $$hash{ $_ }; } keys %{ $hash };
}
sub parameter {
my $self = shift;
my $para = shift;
my $param = $para =~ m/^([^\.]*\.)(.*?)$/i ? $2 : $para;
# return { sub name{ $param; }, sub value{ $self->{ values }->{ $pa
+ra } || ''; } };
my $name = \¶meter_name( $param );
my $val = \¶meter_value( $self->{ values }->{ $para } );
return { $name, $val };
}
sub parameter_name {
my $param = shift;
return $param;
}
sub parameter_value {
my $parval = shift;
return $parval || '';
}
1;
| [reply] [d/l] [select] |
|
|
Since my solution works for a zero or more objects, it also works for a single object.
sub parameter {
...
return NameValTuple->new( name => $name, val => $val );
}
It's still simpler to return a hash since you don't have to create a new class.
sub parameter {
...
return map { +{ name => $_, val => $rv{$_} } } keys(%rv);
}
But you'd have to change
print $_->name, ': ', $_->val, "\n" for $objA->parameter( 'a.x' );
to
print $_->{name}, ': ', $_->{val}, "\n" for $objA->parameter( 'a.x' );
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
|
# In testpar.pl ...
...
print join ': ' , map $_->() , $objA->parameter( 'a.x' );
...
# In A ...
package A;
...
sub parameter
{
...
return
( \¶meter_name( $param )
, \¶meter_value( $self->{ values }->{ $para } )
) ;
}
...
| [reply] [d/l] |
Re: how to let sub return hash of 2 sub?
by stevieb (Canon) on May 27, 2015 at 15:04 UTC
|
Here's one example of a sub returning a hash with two subs, each of which returns something. Without having more context, it's difficult to see exactly what you want long-term, but hopefully this'll give you an idea to get you started.
#!/usr/bin/perl
use strict;
use warnings;
sub fetch_dispatch{
my $dispatch = {
name => sub { return "name = this"; },
val => sub { return "val = that"; },
};
return $dispatch;
}
my $dt = fetch_dispatch();
print $dt->{name}(), ': ', $dt->{val}(), "\n";
-stevieb | [reply] [d/l] |
Re: how to let sub return hash of 2 sub?
by aaron_baugher (Curate) on May 27, 2015 at 19:17 UTC
|
With a bit of extra syntax, you don't have to use objects. :-)
#!/usr/bin/env perl
use 5.010; use strict; use warnings;
# a closure over a hash which takes a key as an argument and returns t
+wo subs
# which return the key and its value from the hash
sub get_caller {
my $h = shift;
return { parameter => sub {
my $k = shift;
my $v = $h->{$k};
return { name => sub { return $k },
val => sub { return $v } };
}
};
}
my $c = get_caller( {'a.x' => 1, 'b.y' => 2, 'c.x' => 3} );
print $_->{name}(), ' : ', $_->{val}(), "\n" for $c->{parameter}('a.x'
+);
I think it would be possible to get rid of some of the curlies and parens and get it down to the simpler syntax of the original, but I'm still working through Higher Order Perl. This "functions that create functions to return functions" stuff gets a little mind-bending.
Aaron B.
Available for small or large Perl jobs and *nix system administration; see my home node.
| [reply] [d/l] |
Re: how to let sub return hash of 2 sub?
by Anonymous Monk on May 27, 2015 at 16:03 UTC
|
As ikegami already said above, for the example line of code you give to work, parameter needs to return objects.
If you want to work with objects, it would probably help if you looked at an OO framework such as Moose or e.g. Moo to make writing your classes easier.
If you want to be enlightened on callbacks, closures, iterators, and using code refs in general, Higher-Order Perl is an excellent read.
Either way however, what you are doing seems like it might be a little overcomplicated, but we can't help you with the underlying task if you don't share what that is :-)
| [reply] [d/l] |