如何在 Perl 模块中创建私有函数?

发布于 2024-07-12 03:43:55 字数 2318 浏览 5 评论 0原文

我正在开发一个小 Perl 模块,由于某种原因,我有一个测试驱动程序脚本,该脚本使用我的新模块调用我认为是私有的函数之一,并且它是成功的。 我很惊讶,所以我开始搜索谷歌,但我找不到任何关于如何在 Perl 模块中创建私有函数的文档...

我看到一个地方说要在“私有”函数的右大括号后添加分号,就像这样:

sub my_private_function {
...
}; 

我尝试过,但我的驱动程序脚本仍然可以访问我想要私有的函数。

我将编写一个更短的示例,但这就是我想要的:

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

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!

所以我在模块中最后一个右大括号后面添加了一个分号,但输出仍然相同。 我真正发现的唯一一件事是将这一行添加为我的 private_function 的第一行:

caller eq __PACKAGE__ or die;

但这看起来很老套。 我没有太多编写 Perl 模块的经验,所以也许我的模块设置不正确? perl 模块中是否可以有私有函数和变量?

谢谢你帮助我学习!

I am working on a little Perl module and for some reason I had the test driver script that was using my new module call one of the functions that I thought would be private, and it was successful. I was surprised, so I started searching google and I couldn't really find any documentation on how to make private functions in Perl modules...

I saw one place that said to put a semicolon after the closing brace of your "private" function, like this:

sub my_private_function {
...
}; 

I tried that, but my driver script could still access the function I wanted to be private.

I'll make up something that will be a shorter example, but here's what I'm after:

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

Driver output:

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!

So I added a semicolon after the last closing brace in the module, but the output is still the same. The only thing I really found was to add this line as the first line to my private_function:

caller eq __PACKAGE__ or die;

But that seems pretty hacky. I don't have a lot of experience writing Perl modules, so maybe I am setting my module up incorrectly? Is it possible to have private functions and variables in perl modules?

Thanks for helping me learn!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

薯片软お妹 2024-07-19 03:43:55

来自 perldoc perltoot (大约文档的四分之一):

Perl 并不限制谁可以使用哪些方法。 这
公共与私有的区别是按照惯例,而不是语法。 (出色地,
除非您使用下面“数据成员作为
变量”。)有时您会看到以以下开头或结尾的方法名称
一两个下划线。 该标记是一种约定,表明
方法仅对该类是私有的,有时是最接近的类的私有方法
熟人,其直接子类。 但这个区别是
Perl 本身不强制执行。 这取决于程序员的表现。

因此,我建议您在“私有”方法的开头添加一两个下划线,以帮助阻止使用。

From perldoc perltoot (about a quarter way through the document):

Perl doesn't impose restrictions on who gets to use which methods. The
public-versus-private distinction is by convention, not syntax. (Well,
unless you use the Alias module described below in "Data Members as
Variables".) Occasionally you'll see method names beginning or ending with
an underscore or two. This marking is a convention indicating that the
methods are private to that class alone and sometimes to its closest
acquaintances, its immediate subclasses. But this distinction is
not enforced by Perl itself. It's up to the programmer to behave.

Therefore, I recommend you put an underscore or two at the beginning of your "private" methods to help dissuade usage.

寄意 2024-07-19 03:43:55

只有将代码引用存储在词法变量中的“The Kludge”,该范围之外的任何人都看不到:

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

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

而且我无法想到一种方法来创建严格的“受保护”字段。

据我所知,就是这样(除了源过滤器......嘘。我没有提到它们......)


编辑:实际上,事实证明我可以可以想出一种非常混乱的方式来保护。 但这可能涉及通过 AUTOLOAD 子传递所有调用。 (!!)

There is only "The Kludge" of storing a code reference in a lexical variable, which no one outside that scope can see:

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

sub public_sub { 
    my $self = shift;

    $priv_func1->( $self );
}

And I can't think of a way to make rigorously "protected" fields.

That's it as far as I know ( besides source filters...shhhh. I didn't mention them.... )


EDIT: Actually, it turns out I can think of a very messy way of doing protected. But it would probably involve passing all calls through the AUTOLOAD sub. (!!)

┈┾☆殇 2024-07-19 03:43:55

这有效:

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

sub public_sub { 
    my $self = shift;

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

This works:

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

sub public_sub { 
    my $self = shift;

    $self->$priv_func1(@_);
}
合久必婚 2024-07-19 03:43:55

只需检查来电者:

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( );

Just check caller:

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( );
左耳近心 2024-07-19 03:43:55

你想做什么? 也许有更好的 Perl 方法来完成您想要完成的任务。

例如,如果您不想让人们在您的对象中乱搞,因为您想强制封装,则可以使用类似 Class::InsideOut。 该模块有一个 Class::InsideOut::About 文档模块来解释这个概念。 还有 Object::InsideOut,Brian Phillips 已经提到过。

What are you trying to do? Maybe there is a better Perl way of doing whatever you are trying to accomplish.

For instance, if you don't want people mucking around in your objects because you want to enforce encapsulation, you can use something like Class::InsideOut. That module has a Class::InsideOut::About documentation module that explains the concept. There is also Object::InsideOut, which Brian Phillips already mentioned.

打小就很酷 2024-07-19 03:43:55

当您意识到不能仅使用 Data::Dumper 直接转储对象或查看对象内部以查看其数据时,这种 OO 风格在一段时间后开始感觉有点“un-perlish”。 但是,如果您想尝试一下,我建议使用 Object::InsideOut< /a>. 它支持对象的私有数据和方法以及许多其他方便的功能(访问器生成、默认构造函数等)。

This style of OO starts to feel a little "un-perlish" after a while when you realize you can't just use Data::Dumper to dump the object directly or peek inside the object to look at its data. However, if you want to give it a shot, I'd recommend using Object::InsideOut. It supports private data and methods for your objects along with a number of other handy features (accessor generation, default constructor, etc).

千柳 2024-07-19 03:43:55

我们可以在 perl 私有函数中编写一些内容来检查来自与 caller[0] 相同的 obj 的调用是否给出了 package.json。

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

We can write some thing below in the perl private function to check whehter the call from the same obj as caller[0] gives package.

sub foo {
  my ($s, %args) = @_;
  die "Error: Private method called"
      unless (caller)[0]->isa( ref($s) );
}
烟柳画桥 2024-07-19 03:43:55

如果您使用像 Moose 这样的系统,您可以获得公共/私有区别,如下所示< a href="http://search.cpan.org/perldoc?MooseX::MethodPrivate" rel="nofollow noreferrer">此处。

If you use a system like Moose, you can get a public/private distinction as seen here.

橘和柠 2024-07-19 03:43:55

在您的包的文件中:将私有方法定义为 CODE-Ref,即:

my $private_methode = sub{};

In File for your package: Define private methods as CODE-Ref, i.e.:

my $private_methode = sub{};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文