gpt4 book ai didi

perl - Perl 中的条件编译

转载 作者:行者123 更新时间:2023-12-02 06:50:15 25 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Is it possible to conditionally "use bigint" with Perl?

(3 个回答)


4年前关闭。




如何使以下代码工作?

use strict;
use warnings;

if ($^O eq 'MSWin32' || $^O eq 'MSWin64') {
use Win32;
Win32::MsgBox("Aloha!", MB_ICONINFORMATION, 'Win32 Msgbox');
}
else {
print "Do not know how to do msgbox under UNIX!\n";
}

以上在Windows下运行。但在 UNIX 下,由于找不到 Win32,会出现编译错误。将“use”替换为“require”会使事情变得更糟——代码将无法在 Windows 和 UNIX 下编译,因为包含 MB_ICONINFORMATION 的行总是被编译,而“MB_ICONINFORMATION”将是一个未声明的裸词。

那么我该如何解决这个问题呢?

最佳答案

Perl 首先将代码编译为中间表示,然后执行它。由于if在运行时评估,但 use在编译期间处理,您不是有条件地导入模块。

为了解决这个问题,有许多可能的策略:

  • 使用 use if 进行条件导入杂注
  • 带 BEGIN block 的条件导入
  • require模块
  • 使用 eval 延迟编译

  • 要仅在满足特定条件时导入模块,可以使用 if pragma :
    use if $^O eq 'MSWin32', 'Win32';

    您还可以通过将代码放入 BEGIN block 中来在编译期间运行代码:
    BEGIN {
    if ($^O eq 'MSWin32') {
    require Win32;
    Win32->import; # probably not necessary
    }
    }

    该 BEGIN block 的行为与上面的 use if 完全相同。 .

    请注意,我们必须使用 require这里。与 use Win32 ,该模块将在开始 block 的编译期间加载,绕过 if .与 require该模块是在开始 block 的运行时加载的,也就是在周围代码的编译期间。

    在这两种情况下, Win32模块只会在 Windows 下导入。剩下的 MB_ICONINFORMATION非 Windows 系统上的常量未定义。在这种代码中,最好不要导入任何符号。取而代之的是,对所有内容使用完全限定名称,并为函数调用使用括号(此处为: Win32::MB_ICONINFORMATION())。有了这个更改,只需使用 require而不是 use if也可以工作。

    如果您需要稍后运行代码,您可以使用 string-eval。但是,这可能会导致安全问题,更难以调试,并且通常速度较慢。例如,您可以这样做:
    if ($^O eq 'MSWin32') {
    eval q{
    use Win32;
    Win32::MsgBox("Aloha!", MB_ICONINFORMATION, 'Win32 Msgbox');
    1;
    } or die $@; # forward any errors
    }

  • 因为eval默认情况下会消除任何错误,您必须检查成功并可能重新抛出异常。 1语句确保经过评估的代码在成功时返回真值。 eval返回 undef如果发生错误。 $@变量保存最后一个错误。
  • q{...}是替代引用结构。除了大括号作为字符串分隔符之外,它与 '...' 完全相同。 (单引号)。

  • 如果你有很多代码只能在某个平台上运行,那么对每个片段使用上述策略是很乏味的。相反,为每个平台创建一个模块。例如。:

    本地/MyWindowsStuff.pm:
    package Local::MyWindowsStuff;
    use strict;
    use warnings;
    use Win32;

    sub show_message {
    my ($class, $title, $contents) = @_;
    Win32::MsgBox("Aloha!", MB_ICONINFORMATION, 'Win32 Msgbox');
    }

    1;

    本地/MyPosixStuff.pm:
    package Local::MyPosixStuff;
    use strict;
    use warnings;

    sub show_message {
    warn "messagebox only supported on Windows";
    }

    1;

    在这里,我将它们编写为可用作类。然后我们可以有条件地加载这些类之一:
    sub load_stuff {
    if ($^O eq 'MSWin32') {
    require Local::MyWindowsStuff;
    return 'Local::MyWindowsStuff';
    }
    require Local::MyPosixStuff;
    return 'Local::MyPosixStuff';
    }

    my $stuff = load_stuff();

    最后,我们没有在代码中添加条件,而是在加载的类上调用方法:
    $stuff->show_message('Aloha!', 'Win32 Msgox');

    如果您不想创建额外的包,一种策略是评估代码引用:
    sub _eval_or_throw { my ($code) = @_; return eval "$code; 1" or die $@ }

    my $show_message =
    ($^O eq 'MSWin32') ? _eval_or_throw q{
    use Win32;
    sub {
    Win32::MsgBox("Aloha!", MB_ICONINFORMATION, 'Win32 Msgbox');
    }
    } : _eval_or_throw q{
    sub {
    warn "messagebox only supported on Windows";
    }
    };

    然后: $show_message->()调用此代码。这样可以避免使用 eval 重复编译相同的代码.当然,仅当此代码在每个脚本中运行多次时才重要,例如在循环内或子程序中。

    关于perl - Perl 中的条件编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46877733/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com