【问题标题】:Perl subroutines and arraysPerl 子例程和数组
【发布时间】:2012-08-09 04:16:19
【问题描述】:

我刚开始使用 Perl(大约 15 分钟前)使用在线教程。我做了一个小子程序来测试一些 Perl 特性,并想知道是否可以在运行时确定传递给 sub' 调用的参数是数组还是标量。以我写的sub为例:

#!/usr/bin/perl

sub somme_prod {
    if (scalar(@_) > 1) {
        $facteur = shift(@_);
        foreach my $nb (@_) {
            $resultat += $nb
        }
        return ($resultat * $facteur);
    }
    else {
        return "ERREUR";
    }
}

print somme_prod(2, 2, 3, 7);

这是一个基本的 sum-product 子例程,其功能完全符合其名称。现在,是否可以修改此子例程以允许像这样混合使用数组和标量?

somme_prod(2, (2,3), 7);
somme_prod(2, (2,3,7));
#...

此外,欢迎对此处演示的 Perl 编码风格发表任何评论非常。我有业余 C++ 编码的背景,所以我可能不会考虑 Perl。

编辑:我很抱歉。实际上,我在发布后尝试过,似乎 Perl 确实按照我的意愿处理了我的 sub。现在我想我的问题会是“Perl 如何知道如何处理这个”?

为更接近 Perl 的版本编辑了代码。

【问题讨论】:

  • 只是关于样式的说明,在 Perl 中,使用 foreach my $thing( @things ) { ... } 来循环数组会更好。
  • 这是我最初的想法,但这使得很难区分要求和的值和因子(它始终是第一个值),除非有我不知道的技巧。
  • 我发现 foreach 有一种变体,它可以将变量转换为索引,从而有效地创建了一个更短且更易于阅读的循环:foreach my $i (1 .. $#_)
  • 为了澄清,只有标量列表可以传入和传出 Perl 子例程;数组不能传递。请参阅Passing arrays to functions in perl 中的ikegami's 讨论。
  • 感谢您的澄清!

标签: arrays perl subroutine


【解决方案1】:

是的;在 Perl 中,您可以创建对数组(或哈希或其他任何东西)的引用,以将多个值填充到单个参数中。

例如:

somme_prod(2, [2, 3], 7);

...将解析为:

sub somme_prod {
  foreach my $arg (@_) {
    if (ref($arg) eq 'ARRAY') {
      my @values = @$arg; # dereference, e.g. [2, 3] -> (2, 3)
      . . .
    } else {
      # single value, e.g. "2" or "7"
    }
  }
}

您可以阅读页面perldoc perlref 以了解有关参考的所有信息。

【讨论】:

  • 不要介意我的评论(如果你在我删除它之前读过它)。感谢您的解释 ! :)
  • 在子程序上使用原型是非常错误的,所以不要这样做。在这里,您的原型坚持认为子例程没有参数,因此它根本停止工作!
  • 小错字。是的,“无括号”或“(@)”将是一个有效的原型。但也不是示例的主要目的。
  • @KevinGrant:不,您应该永远使用原型,除非您正在编写 Perl 内置运算符的替代品。
【解决方案2】:

Perl 处理列表和数组的方式不同,您可以阅读一份有用的文档What is the difference between a list and an array?

Perl 将总是展平嵌套列表(以及列表中的数组)所以

my @data1 = (2, (2, 3), 7);

my @data2 = (2, 3);
my @data1 = (2, @data2, 7);

等价于

my @data1 = (2, 2, 3, 7);

正如 Kevin 所说,如果你想要嵌套数组,你必须在子列表出现的地方放置一个数组reference。因为引用是一个标量,所以它不会被扩展。

您的子程序很好,但使用一些事实上的标准会帮助其他人遵循您的程序。首先约定是子程序如果有错误会返回undef,这样你就可以写

sous_routine($p1, $p2) or die "Erreur";

在这种情况下,零是有效结果的可能性破坏了这一点,但最好还是遵守规则。没有参数的普通return 表示错误

稍微整理一下并使用unlessif 作为语句修饰符就可以了

sub somme_prod {
  return unless @_ > 1;
  my $facteur = shift;
  my $somme = 0;
  $somme += $_ for @_;
  return $somme * $facteur;
}

print somme_prod(2, 2, 3, 7);

【讨论】:

    【解决方案3】:

    您已经了解 Perl 15 分钟?暂时忘记引用

    基本上,传递给子例程的所有内容都是一个数组。事实上,它存储在一个名为@_ 的数组中。

    # /usr/bin/env perl
    
    use strict;   #ALWAYS USE!
    use warnings; #ALWAYS USE!
    
    my @array = qw(member1 member2 member3 member4);
    
    foo(@array, 'scalar', 'scalar', 'scalar');
    
    sub foo {
    
    print "My input is " . join (":", @_) . "\n";
    

    这将打印:

    my input is member1:member2:member3:member4:scalar:scalar:scalar
    

    无法分辨哪些条目来自数组,哪些来自标量。就您的子例程而言,它们都是数组@_ 的成员。


    顺便说一下,Perl 附带了一个名为perldoc 的命令。当有人说要查看perlref 时,您可以在命令行输入perldoc perlref 并查看文档。您也可以访问http://perldoc.perl.org 站点,该站点也包含与perldoc 命令相同的信息。


    现在关于参考......

    Perl 数组的数据元素或哈希值只能包含单个值。它可以是一个字符串,也可以是实数,也可以是整数,还可以是对另一个 Perl 数据结构的引用。这就是所有乐趣和金钱的所在。

    例如,上面的同一子程序foo 可能会获取此信息:

    foo(\@array, 'scalar', 'scalar', 'scalar'); #Note the backslash!
    

    在这种情况下,您不会将@array 的值传递给foo。相反,对数组的引用作为@_ 的第一个数据元素传递。如果您尝试打印出$_[0],您会得到类似ARRAY:6E43832 的信息,它表示数据元素是一个数组并且它在内存中的位置。

    现在,您可以使用ref 函数来查看一条数据是否为引用以及它是引用的类型:

     sub foo {
         foreach my $item (@_) {
    
            if (ref $item eq 'ARRAY') {
               print "This element is a reference to an array\n";
            }
            elsif (ref $item eq 'HASH') {
               print "This element is a reference to a hash\n";
            }
            elsif (ref $item) {   #Mysterious Moe Reference
                print "This element is a reference to a " . lc (ref $item) . "\n";
            }
            else {
                print "This element is a scalar and it's value is '$item'\n";
            }
        }
    }
    

    当然,您对数组的引用可能是一个包含对哈希的引用的数组,其中包含对数组的引用等等。 Perl 附带一个名为Data::Dumper 的模块(您可以使用perldoc 查看有关它的信息),它将打印出整个数据结构。

    这就是面向对象 Perl 的工作方式,因此在一段 Perl 数据中嵌入对其他 Perl 数据结构的引用非常普遍。

    现在,只需熟悉基本的 Perl 及其工作原理。然后,开始在Perldoc 中查看关于Perl referencesvarious tutorials

    【讨论】:

    • 是的,15 分钟(我猜现在是几个小时)。我阅读了一些“备忘单”和“快速参考”,然后阅读了关于主要功能(循环、变量、数组、哈希......)的更彻底的非常基础的教程。哦,感谢您添加的信息。也会查看这些链接:)
    猜你喜欢
    • 1970-01-01
    • 2012-05-30
    • 2012-03-24
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 2021-03-09
    • 1970-01-01
    • 2013-12-24
    相关资源
    最近更新 更多