У меня есть этот код Perl:

my $C;

if($someCondition) {
    my $A = My::Package::A::V1->new();
    my $B = My::Package::B::V1->new();
    $C = My::Package::C::V1->new();
} else {
    my $A = My::Package::A::V2->new();
    my $B = My::Package::B::V2->new();
    $C = My::Package::C::V2->new();
}
# Have fun with $C

Я считаю это слишком избыточным, учитывая, что единственная разница - V1 или V2 на основе $someCondition. Есть ли способ сделать что-то вроде my $A = My::Package::A::V{$someCondition ? 1 : 2}->new();?


Что делать, если у меня также есть:

my $C;
if($someCondition) {
    my $C = Some::Package::Z->new(
      myPackageA => &My::Package::A::V1
    );
} else {
    my $C = Some::Package::Z->new(
      myPackageA => &My::Package::A::V2
    );
}

Для этого я попробовал:

my $api_version;
if($someCondition) {
    $api_version = 'V1';
} else {
    $api_version = 'V2';
}
my $C = Some::Package::Z->new(
    myPackageA => "&My::Package::A::$api_version"
);

Но получаю ошибку: Can't call method new on an undefined value

1
justHelloWorld 4 Окт 2018 в 16:12

1 ответ

Лучший ответ

Вы можете сохранить класс в строке и использовать его для ссылки на пакет:

my $api_version;
if($someCondition) {
    $api_version = 'V1';
} else {
    $api_version = 'V2';
}
die "No API version found" unless $api_version;

my $A = "My::Package::A::$api_version"->new();
my $B = "My::Package::B::$api_version"->new();
my $C = "My::Package::C::$api_version"->new();

# Have fun with $C

Если вы также хотите вызывать функции в пространствах имен (как вы это делаете с расширенным вопросом), простой подход - выключить strict и просто вызвать функции, используя их имя:

my $make_A;
{
    no strict 'refs';
    $make_A = \&{ "My::Package::A::$api_version" };
}
my $C = Some::Package::Z->new(
  myPackageA => $make_A->(),
);
3
Corion 4 Окт 2018 в 14:26