一个Perl子例程有一个常量作为参数,如何在子例程中显示常量名称?

A Perl subroutine has a constant as parameter, how to display the constant name in the subroutine?

提问人:troubadour 提问时间:11/17/2023 更新时间:11/19/2023 访问量:97

问:

一个简单的案例:

use constant MYCO => "myco value";
...
sub example {
   my $var = shift; # contains "myco value"
   # here I would like to print the constant name passed, so "MYCO"
}
...
example(MYCO);
# example(OTHER_CONSTANT1);
...

添加了用于过帐的行 添加了用于过帐的行 添加了用于过帐的行

Perl的

评论

1赞 ikegami 11/17/2023
如果他们这样做了怎么办?example("myco value");
0赞 ikegami 11/17/2023
如果还有呢?use constant ALIAS => "myco value";
0赞 Denis Ibaev 11/21/2023
另请参阅 stackoverflow.com/questions/12581628/...

答:

2赞 Rawley Fowler 11/17/2023 #1

如果不显式提供常量的名称作为其值的一部分,就无法做到这一点。

你可以做这样的事情:

use constant MYCO => ["myco value", "MYCO"];

sub example {
   my $var = shift; # contains "myco value"
   say $var->[0]; # value
   say $var->[1]; # name
}

example(MYCO);
# example(OTHER_CONSTANT1);

老实说,在我看来,这是一种反模式。我更希望有一个子例程(这是Perl在后台对常量所做的,但不做任何保证)。然后只需按名称调用子例程作为参数即可。

sub MYCO { "myco value" }

sub example {
    my $constant_name = shift;
    my $value = __PACKAGE__->can($constant_name)->();

    say $value;
    say $constant_name;
}

example('MYCO');

编辑:在考虑了更多之后,如果你真的需要这个功能,你可能想把你的常量OO化。像这样:

package My::Constant;

sub name { shift->{name} }
sub value { shift->{value} }

sub new {
    my ($class, $name, $value) = @_;

    my $self = {};
    ($self->{value}, $self->{name}) = ($value, $name);

    return bless($self, $class);
}

1;

然后,在现有代码中,您可以更习惯地定义常量,例如:

use My::Constant;

use constant MYCO => My::Constant->new("MYCO", "myco value");

sub example {
    my $var = shift;

    return unless ref($var) eq "My::Constant";

    say $var->name;
    say $var->value;
}

example(MYCO);

评论

0赞 troubadour 11/17/2023
谢谢,但是想象一下示例子例程中使用的许多常量作为参数,使用这种技巧的代码可能会很长.....我只是想知道是否存在一个预定义的函数,子例程中只有一个调用
0赞 Rawley Fowler 11/17/2023
你需要改变你的方法,如果你有大量的常量,并且需要它们的名字,你可能应该重构。
0赞 brian d foy 11/17/2023
这就是我通常的做法。
2赞 ikegami 11/17/2023 #2

除非这个问题没有意义

  • 你把自己限制在特定的常量子集上,
  • 它们都有独特的价值,并且
  • 你不在乎这个常量是否被实际使用。

然后你可以做类似的事情

use constant;

my ( %widget_types, %widget_type_by_val );
BEGIN {
   # Can't have two widget types with the same value.
   %widget_types = (
      FLOOB => 0,
      GRINK => 1,
      BLARP => 2,
   );
   
   %widget_type_name_by_val = reverse( %widget_types );

   constant->import( \%widget_types );
}

sub get_widget_type_name_from_val {
   return $widget_type_name_by_val{ $_[0] };
}

您可以将其放在导出常量的模块中。

package My::Widgets;

use constant;
use Exporter qw( import );

our @EXPORT_OK = qw(
   get_widget_type_name_from_val
);

my ( %widget_types, %widget_type_by_val );
BEGIN {
   # Can't have two widget types with the same value.
   %widget_types = (
      FLOOB => 0,
      GRINK => 1,
      BLARP => 2,
   );
   
   %widget_type_name_by_val = reverse( %widget_types );

   constant->import( \%widget_types );

   push @EXPORT_OK, keys( %widget_types );
}

sub get_widget_type_name_from_val {
   return $widget_type_name_by_val{ $_[0] };
}

1

可能已经有一个模块为您做了类似的事情。