使用对象作为常量有什么问题吗?

时间:2017-05-22 21:36:20

标签: perl

我使用WWW::Mechanize对象作为常量,它对我来说效果很好,但感觉有点奇怪。

use constant MECH => WWW::Mechanize->new(agent => 'my_app');

将对象用作常量是否有“错误”?

3 个答案:

答案 0 :(得分:3)

它基本上没问题,但只有引用是常量。我经常使用常量网址,比如

use constant URL => URI->new('http://www.example.com/');

但如果您实际修改了对象,那么它可能会有点混乱。我从常量克隆来创建一个类似的值,比如

my $url = URL->clone->path('/path/to/resource');
如果您希望使用类似的方法,

WWW::Mechanize也有clone方法。我不认为将它用作变量是合适的,例如

MECH->get($url);

我不明白你为什么要

答案 1 :(得分:2)

不,不是天生就错了。

Perl常量只是一个具有空原型的无法子程序。在您提供的示例中,您可以将MECH视为WWW::Mechanize类实例的访问者。将与MECH常量的任何消费者共享相同的实例。

此:

use constant MECH => WWW::Mechanize->new(agent => 'my_app');

...大致相当于以下代码段:

BEGIN {
    my $mech;
    sub MECH() {
        return $mech //= WWW::Mechanize->new(agent => 'my_app');
    }
}

或者,使用state变量:

sub MECH() {
    state $mech = WWW::Mechanize->new(agent => 'my_app');
    return $mech;
}

答案 2 :(得分:-1)

我的建议是不要这样做。在Perl中使用use constant定义的所谓常量的一件事是有利于实现常量折叠。例如,当您说use constant N_CONNECTIONS => 5perl看到N_CONNECTIONS,{<1}}会在编译时将<{1}}替换为<{em>},从而进一步优化。< / p>

5

看,一大堆代码刚被修剪。或者,

$perl -MO=Deparse -e 'use constant X => 17; if ( X < 5 ) { rand }'
use constant ('X', 17);
'???';
-e syntax OK

$ perl -MO=Deparse -e 'use constant X => 17; $x = X' use constant ('X', 17); $x = 17; -e syntax OK 知道在编译时将文字perl分配给17

让我们看看你的构造评估的内容:

$x

所以,无论你在哪里使用$ perl -MWWW::Mechanize -MO=Deparse -e 'use constant MECH => WWW::Mechanize->new(agent => "my_app"); $x = MECH' use constant ('MECH', 'WWW::Mechanize'->new('agent', 'my_app')); $x = {autocheck => 1, cookie_jar => {COOKIES => {}}, current_form => undef, def_headers => {user-agent => 'my_app'}, forms => undef, handlers => {request_prepare => [{callback => sub { package LWP::UserAgent; use strict; $jar->add_cookie_header($_[0]); } , line => '/Users/.../opt/lib/perl5/site_perl/5.24.0/LWP/UserAgent.pm:755', owner => 'LWP::UserAgent::cookie_jar'}], response_done => [{callback => sub { package LWP::UserAgent; use strict; $jar->extract_cookies($_[0]); } , line => '/Users/.../opt/lib/perl5/site_perl/5.24.0/LWP/UserAgent.pm:758', owner => 'LWP::UserAgent::cookie_jar'}], response_header => [{callback => sub { package LWP::UserAgent; use strict; my($response, $ua) = @_; require HTML::HeadParser; $parser = 'HTML::HeadParser'->new; $parser->xml_mode(1) if $response->content_is_xhtml; $parser->utf8_mode(1) if $] >= 5.008 and $HTML::Parser::VERSION >= 3.4; push @{$$response{'handlers'}{'response_data'};}, {'callback', sub { return unless $parser; unless ($parser->parse($_[3])) { my $h = $parser->header; my $r = $_[0]; foreach my $f ($h->header_field_names) { $r->init_header($f, [$h->header($f)]); } undef $parser; } } }; } , line => '/Users/.../opt/lib/perl5/site_perl/5.24.0/LWP/UserAgent.pm:734', m_media_type => 'html', owner => 'LWP::UserAgent::parse_head'}]}, headers => {}, images => undef, links => undef, local_address => undef, max_redirect => 7, max_size => undef, no_proxy => [()], noproxy => 0, onerror => sub { package WWW::Mechanize; use warnings; use strict; require Carp; return &Carp::croak; } , onwarn => sub { package WWW::Mechanize; use warnings; use strict; require Carp; return &Carp::carp; } , page_stack => [()], protocols_allowed => undef, protocols_forbidden => undef, proxy => {}, quiet => 0, requests_redirectable => ['GET', 'HEAD', 'POST'], show_progress => undef, ssl_opts => {verify_hostname => 1}, stack_depth => 8675309, text => undef, timeout => 180, title => undef, use_eval => 1}; -e syntax OK ,它都会在编译时被这个粗糙的东西所取代。

当然,事情会奏效,但你会故意写这样的东西吗?

由于MECH现在是包中的子例程,因此可以通过外部代码调用它。这对你来说可能并不重要,但确实打破了封装。

现在,我们遇到了另一个问题。 MECH的实例确实不是常量。每次调用方法时,其内部状态都会发生变化。因此,使用常量来指代处于某种状态的东西充其量似乎是不协调的。

看起来你正试图避免将WWW::Mechanize传递给一堆子程序。这是一个很好的方法,可以将您的特定搜寻器封装在一个类中,并为其提供一个$mech类成员。然后,您班级中的方法可以将其称为mech,您无需传递它。

但是,最终,你问了一个主观问题。我试图解释为什么我这是一个好主意。一般来说,使用全局变量是一个坏主意。

如果你不同意我,请继续使用它。