【问题标题】:Matching optional query parameters using the variable name使用变量名匹配可选查询参数
【发布时间】:2017-06-20 20:29:06
【问题描述】:

我想创建一个可选查询参数的哈希值,这些参数有时会传递给我的子例程。有时会传入一个名为welcome的查询参数,其值为1或0。

如果该变量存在,我想将其添加到哈希中。

我创建了一个名为 OPTIONAL_URL_PARAMS 的配置值,它是可以传入的预期参数名称列表:

use constant OPTIONAL_URL_PARAMS => ("welcome")

到目前为止我有:

my $tempParams = {};

if ( $optionalParam ) {

    foreach my $param (@{&OPTIONAL_URL_PARAMS}) {

        if ($optionalParam eq $self->{$param}) {

            $tempParams->{$param} = $optionalParam;
            $tempParams->{$param} =~ s/\s+//g; # strip whitespace 
        }   
    }
}

但这会尝试使用$self->{$param} 而不是其名称。即我希望欢迎匹配 welcome,但它正在尝试匹配 1。

我知道当涉及到哈希中的键时,您可以使用 keys %hash,但是有没有办法使用常规变量来做到这一点?

编辑

我的子程序被间接调用:

my $url_handler = URL::Handler->new($param, $optionalParam); 

sub new { 
    my $class = shift; 
    my $args = @_; 
    my $self = { 
        param          => $args{param}, 
        optionalParams => $args{optionalParam} 
    };
} 

如果$optionalParam的变量名是'welcome',那么我想尝试将它映射到常量welcome

【问题讨论】:

  • 为什么OPTIONAL_URL_PARAMS 是一个函数?这应该是一个常数吗?如果是这样,那么use constant 并使其成为参考。常量不能是列表。它们是标量的。所以("welcome") 被强制进入标量上下文,并且由于它是一个列表,它被转换为列表中的元素数
  • 你的子程序是如何被调用的?是不是类似于my_sub()my_sub(welcome => 1)?如果是后者,您可以先将@_ 填充到哈希中。
  • $self->{$param} 中有什么内容?你没有告诉我们一切。我的回答解释了 1 和常量的问题,但我认为这里还有一些奇怪的地方。
  • @simbabque: “常量不能是列表” 当然可以! constant pragma 将常量实现为子例程,因此它们可以是子例程可以返回的任何内容。例如perl -E "use constant LIST => ( 'a', 'b', 'c'); say for LIST"
  • @Borodin 哎呀。好的,这使我的部分答案不真实。我会编辑/

标签: perl


【解决方案1】:

我想不出除了 Algol 60 之外没有其他语言支持这个想法。它违背了封装的思想,并阻止您使用数组或哈希元素、函数调用、常量或表达式作为调用的实际参数

变量名纯粹是为了方便程序员,与任何正在运行的程序的功能无关。如果您愿意,您可以使用单个数组 @memory 编写代码并使用“变量”$memory[0]$memory[1] 等。但是您将绕过编译器技术中最有用的部分,它允许我们关联可读文本到内存位置。一旦程序运行,最好考虑这些名称​​丢失

被调用的代码应该只对传递的感兴趣,如果作为实际参数传递的变量的名称在子程序中很重要,那将是一场噩梦

如果您能够访问作为参数传递的变量的名称,如果调用看起来像这样,您认为将向子例程 stats 提供什么

stats( ( $base[$i] + 0.6 + sum(@offset{qw/ x y /}) + sum(@aa) ) / @aa )

总之,一般情况下是做不到的。如果您需要将值与名称相关联,那么您可能应该查看哈希


你的代码

my $url_handler = URL::Handler->new($param, $optionalParam); 

sub new { 
    my $class = shift; 
    my $args = @_; 

    my $self = { 
        param          => $args{param}, 
        optionalParams => $args{optionalParam} 
    };
}

有很多问题

您正确地shift 来自参数数组@_ 的类的名称,但随后设置my $args = @_,这会将$args 设置为元素的数量@_ 中剩余的数量。但是$args 的值无关紧要,因为你再也不会使用它了

然后您将$self 设置为一个新的匿名散列,该散列由两个元素创建,使用散列%args 中的值。但是%args 不存在,所以两个元素的值都是undef。如果您将use strictuse warnings 'all' 放在适当的位置,您就会收到警告

您用来访问这个不存在的哈希的键是paramoptionalParam,我认为它们与调用new 的实际参数的名称相匹配不仅仅是巧合

虽然 Perl 的不寻常之处在于它允许以编程方式访问其符号表,但它是一种神秘且不推荐使用的方法。 这些名称对程序和程序员来说基本上是隐藏的,虽然像 Exporter 这样的模块必须操纵符号表才能完成它们的工作,但基础级软件中的任何此类行为都是非常需要避免

最后,在定义 $self 之后,您再也不会使用它了。您应该根据$class 变量(包含字符串URL::Handler)将它祝福到一个类中并从构造函数返回它

希望对你有帮助

【讨论】:

    【解决方案2】:

    编辑

    在 Perl 中,当您将参数传递给子例程时,所有值都被压缩到一个列表中 (reference)。具体来说,如果您将参数传递给sub,则子程序不知道您最初使用的变量的名称。它只知道他们的价值观。因此,如果您需要名称和值,则必须分别传递它们。一种简单的方法是使用哈希。例如,在new():

        my $class = shift;
        my $param = shift;    # The first, required parameter
        my %therest = (@_);   # Optional parameters, if any
    

    然后你可以说URL::Handler->new($param, 'welcome' => 1),而$therest{welcome} 的值将是1。你也可以说

    URL::Handler->new($param, 'welcome'=>1, 'another'=>42);
    

    %therest 将有两个键welcomeanother

    另请参阅 some further discussion 将整个哈希作为参数传递

    原创

    这也可能无法回答问题!

    您评论中对代码的一些想法。

    my $url_handler = URL::Handler->new($param, $optionalParam); 
    sub new { 
        my $class = shift;   # OK; refers to URL::Handler
        my $args = @_;       # Problematic: now $args is the _number_ of args passed (list @_ evaluated in scalar context).
        my $self = { 
            # There is no %args hash, so the next two lines are not doing what you expect.
            # I actually don't know enough perl to know what they do! :)
            param => $args{param},   
            optionalParams => $args{optionalParam} 
        };
    }
    

    一些想法:

    • use strict;use warnings; 在源文件的顶部(如果您还没有的话)。

    【讨论】:

    • @snakespan 根据您的last comment,您无法从参数中返回它来自的变量的名称。
    • 好的,这实际上回答了我的问题。我想当一个变量被传入时,即使你只是传入值,你也能以某种方式从内存中取出变量名并使用它。我将改用哈希,这可能会使生活更轻松。谢谢
    • 作为记录,我可以使用严格和警告,但我虽然没有必要粘贴它,因为它通常是假设的。感谢您的帮助。
    • “我虽然没有必要粘贴 [严格和警告],因为它通常是假设的” 可悲的是,远非如此。仍然有大量程序员回避use strictuse warnings(或者更糟糕的是,写出来并注释掉)主要是因为它们产生了他们不想看到的错误!如果你有 shebang 线,你还应该显示它,因为它可能会影响程序的行为。
    【解决方案3】:

    这不再是一个答案,但我还不能删除它,因为仍在进行讨论以澄清这个问题。

    foreach my $param (@{&OPTIONAL_URL_PARAMS}) {
         # ...
    }
    

    OPTIONAL_URL_PARAMS 的返回值(你已经在这里遇到了一个错误,这就是为什么你有 &,它应该告诉你一些事情......)只是一个列表,而不是一个数组引用。实际上此时它应该会抛出一个错误,因为您不能将1 用作数组引用

    【讨论】:

    • 这仍然不能回答我的问题。简单地说,我想输出变量名“欢迎”而不是它的值。 Perl 有办法做到这一点吗?
    • @snakespan 什么变量的名称为“欢迎”? $param 包含字符串 welcome。我不明白你想做什么。
    • @snakespan 什么变量名?我还是不明白你想做什么。请尝试退后一步,在更广泛的背景下进行解释。
    • simbabque,感谢您与 OP 一起澄清问题!你有我的赞成票。
    • “语言不可知论” 不是一半。我所知道的任何现代语言都没有您想象的功能。我想知道你的想法是从哪里来的?
    猜你喜欢
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 2013-02-13
    相关资源
    最近更新 更多