/ / Como faço funções privadas em um módulo Perl? - perl, módulo, módulo perl, funções privadas

Como faço para criar funções privadas em um módulo Perl? - perl, módulo, módulo perl, funções privadas

Estou trabalhando em um pequeno módulo Perl e para algunsmotivo pelo qual fiz o script do driver de teste que estava usando meu novo módulo chamar uma das funções que eu pensei que seria privada, e foi bem-sucedido. Fiquei surpreso, então comecei a pesquisar no google e realmente não consegui encontrar nenhuma documentação sobre como fazer funções privadas em módulos Perl ...

Eu vi um lugar que dizia para colocar um ponto e vírgula após a chave de fechamento de sua função "privada", assim:

sub my_private_function {
...
};

Eu tentei isso, mas meu script de driver ainda conseguia acessar a função que eu queria tornar privada.

Vou inventar algo que será um exemplo mais curto, mas aqui está o que estou procurando:

Módulo TestPrivate.pm:

package TestPrivate;

require 5.004;

use strict;
use warnings;
use Carp;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

require Exporter;

@ISA = qw(Exporter AutoLoader);

our @EXPORT_OK = qw( public_function );
our @EXPORT    = qw( );

$VERSION = "0.01";

sub new {
my ( $class, %args ) = @_;
my $self = {};
bless( $self, $class );
$self->private_function("THIS SHOULD BE PRIVATE");
$self->{public_variable} = "This is public";
return $self;
}

sub public_function {
my $self     = shift;
my $new_text = shift;
$self->{public_variable} = $new_text;
print "Public Variable: $self->{public_variable}n";
print "Internal Variable: $self->{internal_variable}n";
}

sub private_function {
my $self     = shift;
my $new_text = shift;
$self->{internal_variable} = $new_text;
}

Driver: TestPrivateDriver.pl

#!/usr/bin/perl
use strict;
use TestPrivate "public_function";
my $foo = new TestPrivate();
$foo->public_function("Changed public variable");
$foo->private_function("I changed your private variable");
$foo->public_function("Changed public variable again");
$foo->{internal_variable} = "Yep, I changed your private variable again!";
$foo->public_function("Changed public variable the last time");

Saída do driver:

Public Variable: Changed public variable
Internal Variable: THIS SHOULD BE PRIVATE
Public Variable: Changed public variable again
Internal Variable: I changed your private variable
Public Variable: Changed public variable the last time
Internal Variable: Yep, I changed your private variable again!

Portanto, adicionei um ponto-e-vírgula após a última chave de fechamento no módulo, mas a saída ainda é a mesma. A única coisa que realmente encontrei foi adicionar esta linha como a primeira linha à minha private_function:

caller eq __PACKAGE__ or die;

Mas isso parece muito hacky.Não tenho muita experiência em escrever módulos Perl, então talvez eu esteja configurando meu módulo incorretamente? É possível ter funções e variáveis ​​privadas em módulos Perl?

Obrigado por me ajudar a aprender!

Respostas:

33 para resposta № 1

A partir de perldoc perltoot (cerca de um quarto do documento):

Perl não impõe restrições sobre quem consegueusar quais métodos. O A distinção entre público e privado é por convenção, não por sintaxe. (Nós vamos, a menos que você use o módulo Alias ​​descrito abaixo em "Membros de dados como Variáveis ​​".) Ocasionalmente, você verá nomes de métodos começando ou terminando com um sublinhado ou dois. Esta marcação é uma convenção que indica que o métodos são privados para aquela classe sozinho e às vezes para seu mais próximo conhecidos, suas subclasses imediatas. Mas esta distinção é não reforçado pelo próprio Perl. Cabe ao programador se comportar.

Portanto, recomendo que você coloque um ou dois sublinhados no início de seus métodos "privados" para ajudar a dissuadir o uso.


21 para resposta № 2

Existe apenas "The Kludge" para armazenar uma referência de código em uma variável lexical, que ninguém fora desse escopo pode ver:

my $priv_func1 = sub { my $self = shift; say "func1"; };

sub public_sub {
my $self = shift;

$priv_func1->( $self );
}

E eu não posso pensar de uma maneira de fazer campos rigorosamente "protegidos".

Até onde eu sei (além dos filtros de origem ... shhhh. Eu não os mencionei ...)


EDITAR: Na verdade, acontece que eu posso pense em uma maneira muito complicada de fazer protegido. Mas provavelmente envolveria passar todas as chamadas pelo AUTOLOAD sub. (!!)


14 para resposta № 3

Isso funciona:

my $priv_func1 = sub {
my $self = shift; say "func1";
};

sub public_sub {
my $self = shift;

$self->$priv_func1(@_);
}

8 para resposta № 4

Basta verificar o chamador:

package My;

sub new {
return bless { }, shift;
}

sub private_func {
my ($s, %args) = @_;
die "Error: Private method called"
unless (caller)[0]->isa( ref($s) );

warn "OK: Private method called by " . (caller)[0];
}

sub public_func {
my ($s, %args) = @_;

$s->private_func();
}

package main;

my $obj = My->new();

# This will succeed:
$obj->public_func( );

# This will fail:
$obj->private_func( );

6 para resposta № 5

O que você está tentando fazer? Talvez haja uma maneira melhor em Perl de fazer tudo o que você está tentando realizar.

Por exemplo, se você não quiser que as pessoas mexam em seus objetos porque deseja forçar o encapsulamento, você pode usar algo como Class :: InsideOut. Esse módulo possui um módulo de documentação Class :: InsideOut :: About que explica o conceito. Também há Object :: InsideOut, que Brian Phillips já mencionou.


3 para resposta № 6

Este estilo de OO começa a parecer um pouco"un-perlish" depois de um tempo, quando você perceber que não pode "simplesmente usar Data :: Dumper para despejar o objeto diretamente ou espiar dentro do objeto para ver seus dados. No entanto, se você quiser tentar, eu" eu recomendo usar Object :: InsideOut. Ele suporta dados e métodos privados para seus objetos junto com uma série de outros recursos úteis (geração de acessador, construtor padrão, etc).


3 para resposta № 7

Podemos escrever algo abaixo na função privada perl para verificar se a chamada do mesmo objeto caller[0] dá pacote.

sub foo {
my ($s, %args) = @_;
die "Error: Private method called"
unless (caller)[0]->isa( ref($s) );
}

2 para resposta № 8

Se você usa um sistema como Alce, você pode obter uma distinção público / privado, conforme visto Aqui.


0 para a resposta № 9

Em arquivo para seu pacote: Defina métodos privados como CODE-Ref, ou seja:

my $private_methode = sub{};