改变参数在传递给sub MAIN之前的处理方式 [英] Alter how arguments are processed before they're passed to sub MAIN

查看:62
本文介绍了改变参数在传递给sub MAIN之前的处理方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出文档和有关的评论一个之前的版本问题,根据要求,我做了一个最小的可重现示例,演示了这两个语句之间的区别:

Given the documentation and the comments on an earlier question, by request I've made a minimal reproducible example that demonstrates a difference between these two statements:

my %*SUB-MAIN-OPTS = :named-anywhere;
PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;

只提供一个脚本文件:

#!/usr/bin/env raku
use MyApp::Tools::CLI;

和MyApp/Tools中名为CLI.pm6的模块文件:

and a module file in MyApp/Tools called CLI.pm6:

#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;

proto MAIN(|) is export {*}

multi MAIN( 'add', :h( :$hostnames ) ) {
    for @$hostnames -> $host {
        say $host;
    }
}

multi MAIN( 'remove', *@hostnames ) {
    for @hostnames -> $host {
        say $host;
    }
}

从命令行进行的以下调用不会产生可识别的子例程,但会显示用法:

The following invocation from the command line will not result in a recognized subroutine, but show the usage:

mre.raku add -h=localhost -h=test1

切换 my%* SUB-MAIN-OPTS =:named-anywhere; for PROCESS ::<%SUB-MAIN-OPTS>< named-anywhere>= True; 将按预期显示两行,并提供两个主机名.

Switching my %*SUB-MAIN-OPTS = :named-anywhere; for PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True; will print two lines with the two hostnames provided, as expected.

但是,如果这是在单个文件中完成的,则如下所示,两者的工作原理相同:

If however, this is done in a single file as below, both work identical:

#!/usr/bin/env raku

#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;

proto MAIN(|) is export {*}

multi MAIN( 'add', :h( :$hostnames )) {
    for @$hostnames -> $host {
        say $host;
    }
}

multi MAIN( 'remove', *@hostnames ) {
    for @hostnames -> $host {
        say $host;
    }
}

我觉得这很难理解.当重现此内容时,请注意每个命令的调用方式.

I find this hard to understand. When reproducing this, be alert of how each command must be called.

mre.raku remove localhost test1
mre.raku add -h=localhost -h=test1

因此,当在带有 my%* SUB-MAIN-OPTS =:named-anywhere; 的单独文件中使用命名数组引用时,将无法识别该数组引用.而 PROCESS ::<%SUB-MAIN-OPTS>< named-anywhere>= True; 始终有效.对于一个大胆的数组,两种情况下两者的工作原理是相同的.

So a named array-reference is not recognized when this is used in a separate file with my %*SUB-MAIN-OPTS = :named-anywhere;. While PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True; always works. And for a slurpy array, both work identical in both cases.

推荐答案

问题在于,脚本和模块中的变量都不相同.

The problem is that it isn't the same variable in both the script and in the module.

当然,他们的名字相同,但这并不重要.

Sure they have the same name, but that doesn't mean much.

my \A = anon class Foo {}
my \B = anon class Foo {}

A ~~ B; # False
B ~~ A; # False
A === B; # False

这两个类具有相同的名称,但是是单独的实体.

Those two classes have the same name, but are separate entities.

如果您查看其他内置动态变量的代码,则会看到类似以下内容的

If you look at the code for other built-in dynamic variables, you see something like:

Rakudo::Internals.REGISTER-DYNAMIC: '$*EXECUTABLE-NAME', {
    PROCESS::<$EXECUTABLE-NAME> := $*EXECUTABLE.basename;
}

这可以确保将变量安装在正确的位置,以使其适用于每个编译单元.

This makes sure that the variable is installed into the right place so that it works for every compilation unit.

如果您寻找%* SUB-MAIN-OPTS ,则发现的唯一内容是

If you look for %*SUB-MAIN-OPTS, the only thing you find is this line:

    my %sub-main-opts   := %*SUB-MAIN-OPTS // {};

在主编译单元中查找变量.如果找不到,它将创建并使用一个空哈希.

That looks for the variable in the main compilation unit. If it isn't found it creates and uses an empty Hash.

因此,当您尝试在除主编译单元之外的其他范围内执行此操作时,它不在该行可以找到的位置.

So when you try do it in a scope other than the main compilation unit, it isn't in a place where it could be found by that line.

要测试添加是否可以解决问题,可以将其添加到主编译单元的顶部.(加载模块的脚本.)

To test if adding that fixes the issue, you can add this to the top of the main compilation unit. (The script that loads the module.)

BEGIN Rakudo::Internals.REGISTER-DYNAMIC: '%*SUB-MAIN-OPTS', {
    PROCESS::<%SUB-MAIN-OPTS> := {}
}

然后在模块中编写以下代码:

Then in the module, write this:

%*SUB-MAIN-OPTS = :named-anywhere;

或更妙的是:

%*SUB-MAIN-OPTS<named-anywhere> = True;

尝试此操作后,它似乎工作正常.

After trying this, it seems to work just fine.

问题是,类似

The thing is, that something like that used to be there.

因为它会减慢每个Raku程序的速度而将其删除.

It was removed on the thought that it slows down every Raku program.

尽管我认为它造成的任何减速仍然是一个问题,因为仍然需要查看该行是否存在该名称的动态变量.
(给出了更多的原因,坦率地说,我不同意所有这些原因.)

Though I think that any slowdown it caused would still be an issue as the line that is still there has to look to see if there is a dynamic variable of that name.
(There are more reasons given, and I frankly disagree with all of them.)

这篇关于改变参数在传递给sub MAIN之前的处理方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆