【问题标题】:Private variables in Perl Moose classPerl Moose 类中的私有变量
【发布时间】:2014-05-23 05:57:58
【问题描述】:

我开始使用 Moose 学习 Perl 中的对象。

我不确定我是否理解MooseX::Privacy 的目的。考虑:

use v5.14;

package PA {
    use Moose;
    my $var='private?';
    1;

    sub getVar {
        return $var;
    }
}

package PB {
    use Moose;
    use MooseX::Privacy;

    has 'var' => (
        is => 'rw',
        isa => 'Str',
        default   => 'private?',
        traits => [qw/Private/],
    );
    1;

    sub getVar {
        my $self = shift;
        return $self->var;
    }
}

my $o1= PA->new();
my $o2= PB->new();

say $o1->getVar();
say $o2->getVar();

PAPB 两个类中,我都有一个私有变量var。只有在课堂上PB 我使用MooseX::Privacy。这两种方法有什么区别?我为什么要使用MooseX::Privacy

【问题讨论】:

  • 没有从构造函数参数初始化,没有类型检查,没有强制,没有继承,没有组合,没有自省,没有添加特征的能力,......
  • PA 的 $var 是静态的,PB 不是。除此之外,PA 甚至一开始就使用 Moose 吗?如果您不了解 Moose 的优势,那么整个问题都没有实际意义。
  • @ikegami 我只是在谈论私有变量,所以我不会在这些上使用构造函数初始化?
  • @rutter 我没有在PA 中包含公共变量以使示例最小化..
  • 不确定。我没有 Moose 方便测试。这份清单更多的是给出一个想法,而不是其他任何东西。您的问题基本上是“Moose 提供了哪些优势?”

标签: perl moose


【解决方案1】:

如果您正在寻找 Java 风格的方法隐私,那么 MooseX::Privacy 将会非常令人失望。以下是 Java 风格的方法隐私会发生的情况:

/* This file is called Main.java */
public class Main
{
    public class MyParent
    {
        private String message_string ()
        {
            return "Message from %s\n";
        }

        public void print_message ()
        {
            System.out.printf( this.message_string(), "MyParent" );
        }
    }

    public class MyChild extends MyParent
    {
        public String message_string ()
        {
            return "Another message from %s\n";
        }
    }

    public static void main (String[] args)
    {
        Main o = new Main();
        o.run();
    }

    public void run ()
    {
        MyParent c = new MyChild();
        c.print_message();
    }
}

你可以像这样编译和运行这个例子:

$ javac Main.java
$ java Main
Message from MyParent

注意发生了什么。父类 (MyParent) 将 message_string() 声明为私有方法。子类尝试重写该方法,但遭到彻底拒绝 - 没有给你的汤子类!

现在让我们试试 Perl 和 MooseX::Privacy 的等价物...

# This file is called Main.pl
use v5.14;
use strict;
use warnings;

package MyParent {
    use Moose;
    use MooseX::Privacy;

    private_method message_string => sub {
        my $self = shift;
        return "Message from %s\n";
    };

    sub print_message {
        my $self = shift;
        printf($self->message_string(), __PACKAGE__);
    }
}

package MyChild {
    use Moose; extends qw(MyParent);
    use MooseX::Privacy;

    sub message_string {
        my $self = shift;
        return "Another message from %s\n";
    }
}

my $c = new MyChild();
$c->print_message();

我们可以这样运行:

$ perl Main.pl
Another message from MyParent

说,WHA?!?!?!message_string 不应该是私人的吗?! MyChild到底是怎么覆盖MyParent中的方法的?!

事实上,MooseX::Privacy 并没有像在大多数 OO 语言中实现的那样为您提供接近方法隐私的任何东西。 MooseX::Privacy 类似于在您的方法中执行此操作:

die "GO AWAY!!" unless caller eq __PACKAGE__;

除了 MooseX::Privacy 会为您的所有方法调用增加大量运行时开销。

真的,没有理由使用 MooseX::Privacy。如果您想要私有方法,请将它们放在词法变量中。像这样:

use v5.14;
use strict;
use warnings;

package MyParent {
    use Moose;

    my $message_string = sub {
        my $self = shift;
        return "Message from %s\n";
    };

    sub print_message {
        my $self = shift;
        printf($self->$message_string(), __PACKAGE__);
    }
}

package MyChild {
    use Moose; extends qw(MyParent);

    sub message_string {
        my $self = shift;
        return "Another message from %s\n";
    }
}

my $c = new MyChild();
$c->print_message();

现在运行它:

$ perl Main2.pl
Message from MyParent

哈利路亚!!我们有一个真正的私有方法!

好的,因此您可以在没有 MooseX::Privacy 的情况下使用私有方法,并且它们比 MooseX::Privacy 工作得更好(更快)。

但是私有属性呢?好吧,我有一个关于 CPAN 的小模块可以帮助你:Lexical::Accessor。这是一个为您创建属性的小工具,具有“由内而外”存储(即属性值不会存储在对象的祝福 hashref 中),并将访问器安装在词法变量中(就像私有 @ 987654334@上面的方法)。

无论如何,这就是我对 MooseX::Privacy 的看法。

【讨论】:

  • 感谢有趣的回答!如果print_message 方法被定义在子类而不是父类中会发生什么? (或者如果它在孩子中被覆盖?)
  • 如果print_messageMyChild 中定义,那么它总是可以调用在MyChild 中定义的get_message(无论为get_message 选择什么隐私)。如果print_messageMyChild 中定义,但get_message 是在MyParent 中定义的私有方法,那么在Java 中(并使用我的词法技术),它不能调用get_message,因为它甚至看不到get_message 存在!使用 MooseX::Privacy,它可以看到并调用它,但这样做会引发异常。
猜你喜欢
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 2016-06-26
  • 2011-10-21
  • 2012-08-11
  • 1970-01-01
  • 2015-09-25
相关资源
最近更新 更多