/ / Как да направя частни функции в Perl модул? - perl, модул, perl-модул, частни функции

Как да направя частни функции в Perl модул? - perl, модул, perl-модул, частни функции

Работя по малко Perl модул и за някоипричина имах скрипта на драйвера за тест, който използваше новия ми модул, извиква една от функциите, която мислех, че ще бъде частна, и тя беше успешна. Бях изненадан, затова започнах да търся google и не можах да намеря наистина никаква документация за това как да правя частни функции в Perl модулите ...

Видях едно място, което каза да сложа точка и запетая след затварящата скоба на вашата "частна" функция, като това:

sub my_private_function {
...
};

Опитах това, но драйверът ми все още можеше да получи достъп до функцията, която исках да е частна.

Ще измисля нещо, което ще бъде по-кратък пример, но ето какво правя след:

Модул 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;
}

Драйвер: 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");

Изход на драйвера:

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!

Така че добавих запетая след последната затваряща скоба в модула, но изходът все още е същият. Единственото, което наистина открих, беше да добавя този ред като първи ред към my private_function:

caller eq __PACKAGE__ or die;

Но това изглежда доста гадно. Аз нямам голям опит с писането на модули Perl, така че може би настройвам модула си неправилно? Възможно ли е да има частни функции и променливи в Perl модулите?

Благодаря, че ми помогнах да уча!

Отговори:

33 за отговор № 1

от perldoc perltoot (около една четвърт път през документа):

Perl не налага ограничения за това кой ще стигнеизползвайте кои методи. Най- разграничаването между публично и частно е чрез конвенция, а не синтаксис. (Добре, освен ако не използвате модула Alias, описан по-долу в „Членове на данните като Променливи ".) Понякога ще видите имена на методи, започващи или завършващи с подчертаване или две. Тази маркировка е конвенция, показваща, че методите са частни само за този клас, а понякога и за най-близките му познати, неговите непосредствени подкласове. Но това разграничение е не се налага от самия Перл. От програмиста трябва да се държи.

Ето защо препоръчвам да поставите подчертаване или две в началото на вашите "частни" методи, за да помогнете за разубеждаване на използването.


21 за отговор № 2

Съществува само "The Kludge" за съхраняване на кодова референция в лексикална променлива, която никой извън този обхват не може да види:

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

sub public_sub {
my $self = shift;

$priv_func1->( $self );
}

И не мога „т мисля на начин да се правят строго "защитени" полета.

Това е, доколкото знам (освен филтри на източници ... шххх. ​​Не ги споменавах ....)


РЕДАКТИРАНЕ: Всъщност се оказва, че аз мога помислете за много разхвърлян начин да се защитите. Но това вероятно ще включва преминаване на всички обаждания през AUTOLOAD под. (!!)


14 за отговор № 3

Това работи:

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

sub public_sub {
my $self = shift;

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

8 за отговор № 4

Просто проверете обаждащия се:

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 за отговор № 5

Какво се опитваш да направиш? Може би има по-добър Perl начин да правите всичко, което се опитвате да постигнете.

Например, ако не искате хората да заглушават вашите обекти, защото искате да наложите капсулиране, можете да използвате нещо като Клас :: InsideOut, Този модул има клас :: InsideOut :: относно документация модул, който обяснява концепцията. Има и Обект :: InsideOut, които Брайън Филипс вече спомена.


3 за отговор № 6

Този стил на OO започва да се усеща малко"un-perlish" след известно време, когато осъзнаете, че не можете просто да използвате Data :: Dumper, за да изхвърлите директно обекта или да надникнете вътре в обекта, за да разгледате неговите данни. Въпреки това, ако искате да го изстреляте, аз " d препоръчвам да използвате Обект :: InsideOut, Той поддържа частни данни и методи за вашите обекти, заедно с редица други удобни функции (генериране на аксесоари, конструктор по подразбиране и т.н.).


3 за отговор № 7

Можем да напишем нещо по-долу в частната функция perl, за да проверим дали повикването от същия obj като caller[0] дава пакет.

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

2 за отговор № 8

Ако използвате система като американски лос, можете да получите публично / частно разграничение, както се вижда тук.


0 за отговор № 9

Във Файл за вашия пакет: Определете частните методи като CODE-Ref, т.е.:

my $private_methode = sub{};