/ / Come creo funzioni private in un modulo Perl? - perl, module, perl-module, private-functions

Come posso creare funzioni private in un modulo Perl? - perl, modulo, modulo perl, funzioni private

Sto lavorando su un piccolo modulo Perl e per alcunimotivo per cui lo script del driver di test che utilizzava il mio nuovo modulo chiamava una delle funzioni che pensavo sarebbero state private, e ha avuto successo. Sono rimasto sorpreso, quindi ho iniziato a cercare su Google e non sono riuscito a trovare alcuna documentazione su come creare funzioni private nei moduli Perl ...

Ho visto un punto che diceva di mettere un punto e virgola dopo la parentesi graffa di chiusura della tua funzione "privata", in questo modo:

sub my_private_function {
...
};

L'ho provato, ma il mio script del driver potrebbe ancora accedere alla funzione che volevo fosse privata.

Inventerò qualcosa che sarà un esempio più breve, ma ecco cosa sto cercando:

Modulo 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");

Uscita 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!

Quindi ho aggiunto un punto e virgola dopo l'ultima parentesi graffa di chiusura nel modulo, ma l'output è sempre lo stesso. L'unica cosa che ho davvero trovato è stata aggiungere questa riga come prima riga alla mia funzione_private:

caller eq __PACKAGE__ or die;

Ma sembra piuttosto complicato.Non ho molta esperienza nella scrittura di moduli Perl, quindi forse sto impostando il mio modulo in modo errato? È possibile avere funzioni e variabili private nei moduli Perl?

Grazie per avermi aiutato a imparare!

risposte:

33 per risposta № 1

A partire dal perldoc perltoot (a circa un quarto del documento):

Perl non impone restrizioni su chi può accedereutilizzare quali metodi. Il la distinzione tra pubblico e privato è per convenzione, non sintassi. (Bene, a meno che non utilizzi il modulo Alias ​​descritto di seguito in "Membri dati come Variabili ".) Di tanto in tanto vedrai i nomi dei metodi che iniziano o finiscono con uno o due trattini bassi. Questo marchio è una convenzione che indica che il i metodi sono privati ​​solo di quella classe e talvolta di quella più vicina conoscenti, le sue sottoclassi immediate. Ma questa distinzione lo è non applicato dal Perl stesso. Spetta al programmatore comportarsi bene.

Pertanto, ti consiglio di inserire uno o due trattini bassi all'inizio dei tuoi metodi "privati" per dissuadere l'uso.


21 per risposta № 2

C'è solo "The Kludge" di memorizzare un riferimento al codice in una variabile lessicale, che nessuno al di fuori di tale ambito può vedere:

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

sub public_sub {
my $self = shift;

$priv_func1->( $self );
}

E non posso "t pensare di un modo per realizzare campi rigorosamente "protetti".

Questo è tutto per quanto ne so (oltre ai filtri sorgente ... shhhh. Non li ho citati ....)


MODIFICARE: In realtà, si scopre che io può pensa a un modo molto disordinato di fare protetto. Ma probabilmente implicherebbe il passaggio di tutte le chiamate tramite AUTOLOAD sub. (!!)


14 per risposta № 3

Questo funziona:

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

sub public_sub {
my $self = shift;

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

8 per risposta № 4

Basta controllare il chiamante:

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 per risposta № 5

Cosa stai cercando di fare? Forse c'è un modo migliore Perl di fare qualunque cosa tu stia cercando di realizzare.

Ad esempio, se non vuoi che le persone si muovano nei tuoi oggetti perché vuoi imporre l'incapsulamento, puoi usare qualcosa come Classe :: InsideOut. Quel modulo ha un modulo di documentazione Class :: InsideOut :: About che spiega il concetto. C'è anche Oggetto :: InsideOut, che Brian Phillips ha già menzionato.


3 per risposta № 6

Questo stile di OO inizia a sembrare un po '"un-perlish" dopo un po 'quando ti rendi conto che non puoi semplicemente usare Data :: Dumper per scaricare direttamente l'oggetto o sbirciare all'interno dell'oggetto per guardare i suoi dati. Tuttavia, se vuoi provarlo, io " d consiglia di utilizzare Oggetto :: InsideOut. Supporta dati e metodi privati ​​per i tuoi oggetti insieme a una serie di altre utili funzionalità (generazione di funzioni di accesso, costruttore predefinito, ecc.).


3 per risposta № 7

Possiamo scrivere qualcosa di seguito nella funzione private perl per controllare se la chiamata dallo stesso oggetto di caller[0] dà il pacchetto.

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

2 per risposta № 8

Se usi un sistema come alce americano, puoi ottenere una distinzione pubblico / privato come visto Qui.


0 per risposta № 9

In File per il tuo pacchetto: Definisci metodi privati ​​come CODE-Ref, ovvero:

my $private_methode = sub{};