Domanda

Ho una serie di costanti dichiarato in Perl:

   use constant C1 => 111;
   use constant C2 => 222;
   ..
   use constant C9 => 999;
   my $which_constant = "C2";

Come faccio a costruire un'espressione Perl che, sulla base $which_constant, deriva il valore di una costante denominata con il valore di questa variabile - per esempio "222".

Si prega di notare che non riesco a modificare le condizioni di cui sopra - sono una semplificazione di uno scenario reale: ho un modulo (che non ho alcun controllo su) dal quale sono importati queste costanti. Il `nome di una delle costanti è fornita dall'utente da linea di comando. Ho bisogno di accedere il valore delle costanti del caso.

mi è stato battendo la testa contro il muro (per lo più intorno a tutti i tipi di costrutti glob strano), ma nessuno di loro lavoro.

P.S. Se la soluzione accede ai costanti all'interno del loro nativa modulo - My::Constants::C2 dire (senza bisogno di importarli), ancora meglio, ma non è necessario - posso importare le costanti corretti in main:: facilmente utilizzando My::Constants->import($which_constant). e sì, per di più fuori, te le costanti non vengono esportati per default che necessitano quindi la chiamata esplicita di importazione ().

Alcune delle cose che ho provato:

  • main::$which_constant - errore di sintassi

  • main::${which_constant} - errore di sintassi

  • ${*$which_constant} - restituisce valore vuoto

  • *$which_constant - restituisce "* main :: C2"

  • ${*${*which_constant}} - vuoto

È stato utile?

Soluzione

constant.pm sono solo subroutine. È possibile utilizzare la sintassi invocazione metodo se si dispone il nome della costante in una stringa:

#!/usr/bin/perl -l

use strict; use warnings;
use constant C1 => 111;
use constant C2 => 222;

print __PACKAGE__->$_ for qw( C1 C2 );
# or print main->$_ for qw( C1 C2 );

In questo modo, se si tenta di utilizzare una costante che non è definito, si otterrà un errore.

Altri suggerimenti

Perl "costanti" sono in realtà subroutine che restituiscono un valore costante. Il compilatore Perl è in grado di sostituirli con il valore appropriato in fase di compilazione. Tuttavia, dal momento che si desidera ottenere il valore sulla base di una ricerca del nome di runtime, si dovrebbe fare:

&{$which_constant}();

(E naturalmente è necessario no strict 'refs' da qualche parte.)

Il suggerimento di Sinan alla semantica utilizzare il metodo di invocazione per aggirare i limiti strict 'refs' è il più pulito, più facile da leggere soluzione.

La mia unica preoccupazione era che la pena di velocità per l'utilizzo di questo approccio potrebbe essere un problema. Abbiamo tutti sentito parlare di sanzioni prestazioni metodo di chiamata ei vantaggi di velocità di funzioni inlineable.

Così ho deciso di correre un punto di riferimento (codice e risultati seguono).

I risultati mostrano che normali, costanti inline eseguire circa due volte più veloce chiamate di metodo con un nome di subroutine letterale, e quasi tre volte più velocemente le chiamate di metodo con i nomi di subroutine variabili. L'approccio più lento è un deref standard ed invocazione no strict "refs";.

Ma, anche l'approccio più lento è maledettamente veloce a oltre 1,4 milioni di volte al secondo sul mio sistema.

Questi benchmark obliterare il mio unico prenotazione sull'utilizzo del metodo chiamata di metodo per risolvere questo problema.

use strict;
use warnings;

use Benchmark qw(cmpthese);

my $class = 'MyConstant';
my $name  = 'VALUE';
my $full_name = $class.'::'.$name;


cmpthese( 10_000_000, {
    'Normal'      => \&normal_constant,
    'Deref'       => \&direct_deref,
    'Deref_Amp'   => \&direct_deref_with_amp,
    'Lit_P_Lit_N' => \&method_lit_pkg_lit_name,
    'Lit_P_Var_N' => \&method_lit_pkg_var_name,
    'Var_P_Lit_N' => \&method_var_pkg_lit_name,
    'Var_P_Var_N' => \&method_var_pkg_var_name,
});

sub method_lit_pkg_lit_name {
    return 7 + MyConstant->VALUE;
}

sub method_lit_pkg_var_name {
    return 7 + MyConstant->$name;
}

sub method_var_pkg_lit_name {
    return 7 + $class->VALUE;
}

sub method_var_pkg_var_name {
    return 7 + $class->$name;
}

sub direct_deref {
    no strict 'refs';
    return 7 + $full_name->();
}

sub direct_deref_with_amp {
    no strict 'refs';
    return 7 + &$full_name;
}

sub normal_constant {
    return 7 + MyConstant::VALUE();
}

BEGIN {
    package MyConstant;

    use constant VALUE => 32;
}

E i risultati:

                 Rate Deref_Amp Deref Var_P_Var_N Lit_P_Var_N Lit_P_Lit_N Var_P_Lit_N Normal
Deref_Amp   1431639/s        --   -0%         -9%        -10%        -29%        -35%   -67%
Deref       1438435/s        0%    --         -9%        -10%        -28%        -35%   -67%
Var_P_Var_N 1572574/s       10%    9%          --         -1%        -22%        -29%   -64%
Lit_P_Var_N 1592103/s       11%   11%          1%          --        -21%        -28%   -63%
Lit_P_Lit_N 2006421/s       40%   39%         28%         26%          --         -9%   -54%
Var_P_Lit_N 2214349/s       55%   54%         41%         39%         10%          --   -49%
Normal      4353505/s      204%  203%        177%        173%        117%         97%     --

I risultati generati con ActivePerl 826 su Windows XP, YMMV.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top