How is public keyword used in perl?
I have seen code like this
package xyz;
# putting the module inside its own pair of braces
{
public _foo => my %_foo;
public _bar => my %_bar;
# some subroutines..
}
1;
My question is what exactly is the m开发者_JAVA技巧eaning of the declaration public _foo => my %_foo; I mean how is the public keyword used, and why are we using the big arrow to assign another hash?
Any help would be greatly appreciated.
Oh, are you using Class::InsideOut?
In this case, it's not a keyword, it's actually a subroutine. It sets up a storage variable in the package, to be used as a class attribute.
Basically, an Inside-Out object is a way to get true encapsulation in Perl. Normally, Perl objects store their values inside a hash reference, which is then returned to the user, like this:
package Foo;
use strict;
use warnings;
sub new {
my ($class, %args) = @_;
return bless {
foo => $args{foo},
bar => $args{bar},
}, $class;
}
sub get_foo {
my $self = shift;
return $self->{foo};
}
sub get_bar {
my $self = shift;
return $self->{bar};
}
1;
As you can see, the details of what the class holds actually get returned to the user! They can muck about with it all they want without using accessors. Whups.
Inside out objects use the fact that lexical variables inside a package (such as my
variables) can not EVER be seen outside of their scope. It uses fact that every unique scalar reference has an address that is unique, giving us a unique key into the hash, allowing us to have a unique, restricted stash for class data. The basic pattern looks like this:
package Foo;
use strict;
use warnings;
use Scalar::Util qw/refaddr/;
{
my %_foo_of;
my %_bar_of;
sub new {
my ($class, %args) = @_;
# create a reference to an anonymous scalar.
my $instance = \do { my $anon_scalar };
$_foo_of{ refaddr $instance } = $args{foo};
$_bar_of{ refaddr $instance } = $args{bar};
return $instance;
}
# we have to manually delete these since they don't go out of scope
# automatically like standard Perl classes do!
sub DESTROY {
my $self = shift;
delete $_foo_of{ refaddr $self };
delete $_bar_of{ refaddr $self };
}
sub get_foo {
my $self = shift;
return $_foo_of{ refaddr $self };
}
sub get_bar {
my $self = shift;
return $_bar_of{ refaddr $self };
}
}
1;
Ewwww. Lots of boilerplate. Lots more template work. Annoying.
Now lets look at it with Class::InsideOut
.
package Foo;
use strict;
use warnings;
use Class::InsideOut qw/new public/;
public foo => my %foo;
public bar => my %bar;
1;
DONE!
You can make a more complex new
subroutine if you want, but this automatically sets up a default new
subroutine that initializes foo
and bar
from named arguments.
Class::InsideOut makes it so you don't have to do that boilerplate stuff. It makes your accessors, it makes your anonymous scalar for you, it makes your destructor, and gives it you the nice id
keyword instead of refaddr. Other than that, everything is the same. It just gets rid of some of the boilerplate stuff you normally have to deal with, making inside out classes easy (and fun!) to use.
精彩评论