如何减少常量的重复?

发布于 2024-07-07 01:21:42 字数 939 浏览 7 评论 0原文

我有这个 Perl 脚本,其中包含许多已定义的配置文件常量。 例如:

use constant  {
LOG_DIR                             => "/var/log/",
LOG_FILENAME                        => "/var/log/file1.log",
LOG4PERL_CONF_FILE                  => "/etc/app1/log4perl.conf",
CONF_FILE1                          => "/etc/app1/config1.xml",
CONF_FILE2                          => "/etc/app1/config2.xml",
CONF_FILE3                          => "/etc/app1/config3.xml",
CONF_FILE4                          => "/etc/app1/config4.xml",
CONF_FILE5                          => "/etc/app1/config5.xml",
};

我想减少“/etc/app1”和“/var/log”的重复,但使用变量不起作用。 此外,使用先前定义的常量在同一“使用常量块”中不起作用。 例如:

use constant {
LOG_DIR                             => "/var/log/",
FILE_FILENAME                       => LOG_DIR . "file1.log" 
};

不起作用。

使用单独的“使用常量”块确实可以解决此问题,但这会添加大量不需要的代码。

这样做的正确方法是什么?

I have this Perl script with many defined constants of configuration files. For example:

use constant  {
LOG_DIR                             => "/var/log/",
LOG_FILENAME                        => "/var/log/file1.log",
LOG4PERL_CONF_FILE                  => "/etc/app1/log4perl.conf",
CONF_FILE1                          => "/etc/app1/config1.xml",
CONF_FILE2                          => "/etc/app1/config2.xml",
CONF_FILE3                          => "/etc/app1/config3.xml",
CONF_FILE4                          => "/etc/app1/config4.xml",
CONF_FILE5                          => "/etc/app1/config5.xml",
};

I want to reduce duplication of "/etc/app1" and "/var/log" , but using variables does not work. Also using previously defined constants does not work in the same "use constant block". For example:

use constant {
LOG_DIR                             => "/var/log/",
FILE_FILENAME                       => LOG_DIR . "file1.log" 
};

does not work.

Using separate "use constant" blocks does workaround this problem, but that adds a lot of unneeded code.

What is the correct way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

岁月如刀 2024-07-14 01:21:42

根据您所做的事情,您可能根本不需要常量。 大多数情况下,我编写的东西是其他人用来完成他们的工作的,所以我以一种为其他程序员提供灵活性的方式解决这个问题。 我将这些东西变成方法:

 sub base_log_dir { '...' }

 sub get_log_file {
      my( $self, $number ) = @_;

      my $log_file = catfile( 
        $self->base_log_dir, 
        sprintf "foo%03d", $number
        );
      }

通过这样做,我可以轻松地扩展或重写东西。

但这样做会失去不断折叠的价值,所以你必须考虑这对你来说有多重要。

Depending on what you are doing, you might not want constants at all. Mostly, I write stuff that other people use to get their stuff done, so I solve this problem in a way that gives other programmers flexibility. I make these things into methods:

 sub base_log_dir { '...' }

 sub get_log_file {
      my( $self, $number ) = @_;

      my $log_file = catfile( 
        $self->base_log_dir, 
        sprintf "foo%03d", $number
        );
      }

By doing it this way, I can easily extend or override things.

Doing this loses the value of constant folding though, so you have to think about how important that is to you.

口干舌燥 2024-07-14 01:21:42
use constant +{
    map { sprintf $_, '/var/log' } (
        LOG_DIR            => "%s/",
        LOG_FILENAME       => "%s/file1.log",
    ),
    map { sprintf $_, '/etc/app1' } (
        LOG4PERL_CONF_FILE => "%s/log4perl.conf",
        CONF_FILE1         => "%s/config1.xml",
        CONF_FILE2         => "%s/config2.xml",
        CONF_FILE3         => "%s/config3.xml",
        CONF_FILE4         => "%s/config4.xml",
        CONF_FILE5         => "%s/config5.xml",
    ),
};
use constant +{
    map { sprintf $_, '/var/log' } (
        LOG_DIR            => "%s/",
        LOG_FILENAME       => "%s/file1.log",
    ),
    map { sprintf $_, '/etc/app1' } (
        LOG4PERL_CONF_FILE => "%s/log4perl.conf",
        CONF_FILE1         => "%s/config1.xml",
        CONF_FILE2         => "%s/config2.xml",
        CONF_FILE3         => "%s/config3.xml",
        CONF_FILE4         => "%s/config4.xml",
        CONF_FILE5         => "%s/config5.xml",
    ),
};
梓梦 2024-07-14 01:21:42

遗憾的是,这是行不通的。 原因是您在定义函数(“常量”)之前使用它们。 您可以在调用 constant->import 之前评估它们。

使用变量不起作用,因为 use 语句是在编译时评估的。 分配给变量仅在运行时完成,因此它们还没有被定义。

我能给出的唯一解决方案是将其拆分为多个 useconstant 语句。 在这种情况下,需要两条语句(一条用于 LOG_DIRCONF_DIR,另一条用于其余部分)。

That's not going to work, sadly. The reason for this is that you are using functions ('constants') before they are defined. You evaluate them before the call to constant->import.

Using variables doesn't work because use statements are evaluated at compile time. Assigning to variables is only done at runtime, so they won't be defined yet.

The only solution I can give is to split it into multiple use constant statements. In this case, two statements will do (one for LOG_DIR and CONF_DIR, another for the rest).

耀眼的星火 2024-07-14 01:21:42

我可能会这样写:

use Readonly;

Readonly my $LOG_DIR            => "/var/log";
Readonly my $LOG_FILENAME       => "$LOG_DIR/file1.log";
Readonly my $ETC                => '/etc/app1';
Readonly my $LOG4PERL_CONF_FILE => "$ETC/log4perl.con";

# hash because we don't have an index '0'
Readonly my %CONF_FILES => map { $_ => "$ETC/config$_.xml" } 1 .. 5;

然而,这仍然是很多代码,但它确实消除了重复,这是一个胜利。

为什么你的日志文件是数字的? 如果它们以 0 开头,则数组是比哈希更好的选择。 如果它们被命名,它们就更具描述性。

I'd probably write it like this:

use Readonly;

Readonly my $LOG_DIR            => "/var/log";
Readonly my $LOG_FILENAME       => "$LOG_DIR/file1.log";
Readonly my $ETC                => '/etc/app1';
Readonly my $LOG4PERL_CONF_FILE => "$ETC/log4perl.con";

# hash because we don't have an index '0'
Readonly my %CONF_FILES => map { $_ => "$ETC/config$_.xml" } 1 .. 5;

However, that's still a lot of code, but it does remove the duplication and that's a win.

Why are your logfiles numeric? If they start with 0, an array is a better choice than a hash. If they're named, they're more descriptive.

ゃ人海孤独症 2024-07-14 01:21:42

使用单独的“使用常量”块
确实解决了这个问题,但是
添加了很多不需要的代码。

真的吗?

use constant BASE_PATH => "/etc/app1";

use constant  {
    LOG4PERL_CONF_FILE                  => BASE_PATH . "/log4perl.conf",
    CONF_FILE1                          => BASE_PATH . "/config1.xml",
    CONF_FILE2                          => BASE_PATH . "/config2.xml",
    CONF_FILE3                          => BASE_PATH . "/config3.xml",
    CONF_FILE4                          => BASE_PATH . "/config4.xml",
    CONF_FILE5                          => BASE_PATH . "/config5.xml",
};

我认为这没有太多问题。 您仅在一点指定了基本路径,从而遵守了 DRY 原则。 如果您为 BASE_PATH 分配一个环境变量:

use constant BASE_PATH => $ENV{MY_BASE_PATH} || "/etc/app1";

...那么您就有一种廉价的方法来重新配置常量,而无需编辑代码。 这有什么不喜欢的呢?

如果你真的想减少重复的“BASE_PATH”串联,你可以添加一些机制来自己安装常量并将其分解:

use strict;
use warnings;

use constant BASE_PATH => $ENV{MY_PATH} || '/etc/apps';

BEGIN {
    my %conf = (
        FILE1 => "/config1.xml",
        FILE2 => "/config2.xml",
    );

    for my $constant (keys %conf) {
        no strict 'refs';
        *{__PACKAGE__ . "::CONF_$constant"}
            = sub () {BASE_PATH . "$conf{$constant}"};
    }
}

print "Config is ", CONF_FILE1, ".\n";

但在这一点上,我认为平衡已经从正确转向了讨厌:)一开始,您不能再 grep 查找 CONF_FILE1 并查看它的定义位置。

Using separate "use constant" blocks
does workaround this problem, but that
adds a lot of unneeded code.

Does it really?

use constant BASE_PATH => "/etc/app1";

use constant  {
    LOG4PERL_CONF_FILE                  => BASE_PATH . "/log4perl.conf",
    CONF_FILE1                          => BASE_PATH . "/config1.xml",
    CONF_FILE2                          => BASE_PATH . "/config2.xml",
    CONF_FILE3                          => BASE_PATH . "/config3.xml",
    CONF_FILE4                          => BASE_PATH . "/config4.xml",
    CONF_FILE5                          => BASE_PATH . "/config5.xml",
};

I don't see a lot of problems with this. You have specified the base path in one point only, thereby respecting the DRY principle. If you assign BASE_PATH with an environment variable:

use constant BASE_PATH => $ENV{MY_BASE_PATH} || "/etc/app1";

... you then have a cheap way of reconfiguring your constant without having to edit your code. What's there to not like about this?

If you really want to cut down the repetitive "BASE_PATH . " concatenation, you could add a bit of machinery to install the constants yourself and factor that away:

use strict;
use warnings;

use constant BASE_PATH => $ENV{MY_PATH} || '/etc/apps';

BEGIN {
    my %conf = (
        FILE1 => "/config1.xml",
        FILE2 => "/config2.xml",
    );

    for my $constant (keys %conf) {
        no strict 'refs';
        *{__PACKAGE__ . "::CONF_$constant"}
            = sub () {BASE_PATH . "$conf{$constant}"};
    }
}

print "Config is ", CONF_FILE1, ".\n";

But at this point I think the balance has swung away from Correct to Nasty :) For a start, you can no longer grep for CONF_FILE1 and see where it is defined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文