Есть ли в Perl что-то похожее на константу PHP ()? - PullRequest
5 голосов
/ 06 октября 2009

Я немного покопался в perldoc и книгах О'Рейли, но не нашел способа сделать это. Я вынужден использовать что-то вроде Readonly ?

UPDATE:

Я ничего не имею против Readonly. Я просто хотел иметь возможность сделать что-то вроде константы PHP ().

Пример, если Perl имел константу ():

use constant {
  FIELD_EXAMPLE_O => 345,
  FIELD_EXAMPLE_L => 25
};

my $var = 'EXAMPLE';
my $c = 'FIELD_' . $var . '_L';
my $value = constant($c);

# $value is 25

Если Readonly - лучший способ сделать это, тогда я воспользуюсь им.

Ответы [ 7 ]

15 голосов
/ 06 октября 2009

Что не так с Readonly?

Если он слишком медленный, вы можете дополнить его Readonly:XS.Но если вам не нравится Readonly, всегда есть старшее constant.

use constant PI => 3.14159265;

Просто запомните

  1. Они работают как сабвуферы, поэтому не работают без работы.
  2. Если вы хотите создать несколько константв одном операторе вам нужно передать ссылку на хеш.

    use constant { PI => 3.14159265
                 , E  => 2.71828183
                 };
    

Из вашего примера:

Судя по вашему примеру, нет никаких причин, по которым хэш 10 * * readonly не может сделать то же самое.

Readonly::Hash my %field_example => { L => 25, O => 345 };

Тогда вы можете использовать его в любом месте, где захотите мощь константы:

print "The example is $field_example{$var}\n";

ИЛИ вы можете сделать это так:

Readonly::Hash my %field 
    => { example => { L => 25,     O => 345 }
       , name    => { L => 'Lion', O => 'ocelot' }
       };

И назовите это так:

$field{$var}{L};

Вы можете получить много пользы от попыток заставить язык делать то, что он лучше поддерживает, чем-то другим.

Cognate to PHP constant

Однако, если вы хотите сделать это таким образом, то я предлагаю, чтобы следующий подпрограмма была способом сделать то же самое (и избегать eval):

sub read_constant { 
    use Symbol qw<qualify_to_ref>;
    my $name = join( '', @_ ); # no need to concatenate before passing
    my $constant;
    # use the first that works: calling package and then "" (main)
    for my $pkg ( scalar( caller ), "" ) { 
        # get symbol reference
        my $symb_ref = qualify_to_ref( $name, $pkg );
        # get the code slot
        $constant    = *{$symb_ref}{CODE};
        last if $constant;
    }
    return unless $constant;
    # call the sub named
    return $constant->();
}

Вы бы назвали это так:

$value = read_constant( 'FIELD_', $var, 'L' );

И последнее: вы можете даже поставить тест перед собой, чтобы убедиться, что он толькострока со всеми заглавными буквами:

Carp::croak "Invalid constant name '$name'" if $name =~ /[^\p{UpperCase}_]/;
10 голосов
/ 06 октября 2009

Вы можете использовать constant.

use constant PI    => 4 * atan2(1, 1);
use constant DEBUG => 0;

print "Pi equals ", PI, "...\n" if DEBUG;

use constant {
    SEC   => 0,
    MIN   => 1,
    HOUR  => 2,
    MDAY  => 3,
    MON   => 4,
    YEAR  => 5,
    WDAY  => 6,
    YDAY  => 7,
    ISDST => 8,
};

use constant WEEKDAYS => qw(
    Sunday Monday Tuesday Wednesday Thursday Friday Saturday
);

print "Today is ", (WEEKDAYS)[ (localtime)[WDAY] ], ".\n";

Или вы можете использовать Readonly.

use Readonly;

# Read-only scalar
Readonly::Scalar     $sca => $initial_value;
Readonly::Scalar  my $sca => $initial_value;

# Read-only array
Readonly::Array      @arr => @values;
Readonly::Array   my @arr => @values;

# Read-only hash
Readonly::Hash       %has => (key => value, key => value, ...);
Readonly::Hash    my %has => (key => value, key => value, ...);
# or:
Readonly::Hash       %has => {key => value, key => value, ...};

# You can use the read-only variables like any regular variables:
print $sca;
$something = $sca + $arr[2];
next if $has{$some_key};

# But if you try to modify a value, your program will die:
$sca = 7;
push @arr, 'seven';
delete $has{key};
# The error message is "Modification of a read-only value attempted"
7 голосов
/ 06 октября 2009

Да. См. perldoc constant.

4 голосов
/ 06 октября 2009

Вот функция constant, которую вы ищете:

sub constant
{
  no strict 'refs';
  shift->();                    # Call the supplied function by name
} # end constant

Просто добавьте это к коду в вашем вопросе, и он сделает то, что вы просили. Константы, созданные прагмой constant , являются просто подпрограммами, и их легко назвать по имени.

Вот более продвинутый вариант, который все еще работает, даже если вы вызываете его из другого пакета:

sub constant
{
  my $constant = shift;
  $constant = caller() . "::$constant" unless $constant =~ /::/;
  no strict 'refs';
  $constant->();                # Call function by name
} # end constant
1 голос
/ 07 октября 2009

Глядя на пример кода, который вы разместили, я чувствую, что вы можете искать Hash :: Util :: lock_hash и друзей:

#!/usr/bin/perl

use strict;
use warnings;

use Hash::Util qw(lock_hash);

my %constant = (
    FIELD_EXAMPLE_O => 345,
    FIELD_EXAMPLE_L => 25,
);

lock_hash %constant;

my $var = 'EXAMPLE';

print $constant{"FIELD_${var}_L"}, "\n";

Выход:

C:\Temp> xuk
25
1 голос
/ 06 октября 2009

Вы можете использовать прагму «использовать константу», но константы, определенные таким образом, не ссылаются как обычные переменные. Они, тем не менее, дают вам повышение производительности при наличии констант. Если вы не ищете оптимизацию во время компиляции с использованием константы, ваш лучший подход, вероятно, просто использовать дисциплину при написании кода, а не присваивать переменные, которые не должны назначаться. :)

0 голосов
/ 06 октября 2009

Используйте этот формат:

use constant DFLT_MIN_LENGTH_PWD => 6;
...