【问题标题】:Data types for parameters of subroutines / functions?子程序/函数参数的数据类型?
【发布时间】:2012-09-27 10:19:56
【问题描述】:

在 Perl 中,可以为子程序的参数指定数据类型吗?例如。在诸如 exit 之类的数字上下文中使用对偶变量时:

use constant NOTIFY_DIE_MAIL_SEND_FAILED       => dualvar 3, 'NOTIFY_DIE_MAIL_SEND_FAILED';
exit NOTIFY_DIE_MAIL_SEND_FAILED;

在这种情况下,Perl 如何知道 exit 需要一个数字参数?我没有看到像在 Java 中那样为子例程的参数定义数据类型的方法? (我可以理解数据类型是如何被明确定义的)

【问题讨论】:

    标签: perl


    【解决方案1】:

    dualvar 的全部意义在于它根据您的需要表现为数字或文本。在不明显的情况下(对您而言比对 perl 更重要),请明确说明。

    exit 0 + NOTIFY_DIE_MAIL_SEND_FAILED;
    

    至于显式键入参数,这不是内置的。Perl 是一种比 Java 更动态的语言,因此检查/强制每个参数或变量的类型并不常见。特别是,perl sub 可以接受不同数量的参数甚至不同的结构。

    如果您想验证参数(例如对于外部 API),请尝试类似 Params::Validate

    此外,MooseMoo 允许一定程度的属性类型甚至强制。

    【讨论】:

      【解决方案2】:

      在 Perl 中,标量同时是数字和字符串。区分字符串和数字的不是变量本身,而是您使用的运算符。加法+ 仅使用数字,而串联. 仅使用字符串。

      在更强类型的语言中,例如Java中,加法运算符兼作加法和连接运算符,因为它可以访问类型信息。

      "1" + 2 + 3 在 Java 中仍然存在问题,而 Perl 可以清楚地区分 "1" + 2 + 3 == 6"1" . 2 . 3 eq "123"

      您可以通过添加0 或连接空字符串来强制变量的数字或字符串上下文:

      sub foo {
        my ($var) = @_;
        $var += 0;  # $var is numeric
        $var .= ""; # $var is stringy now
      }
      

      【讨论】:

        【解决方案3】:

        Perl 与 Java 的不同之处在于 - Perldynamically typed 语言,因为它不需要在 compile time 处键入其变量。 而Javastatically typed(你已经知道了)

        Perl 根据所使用的context 确定变量的类型..

        只能有two context: -

        • 列表上下文
        • 标量上下文

        上下文由使用的operatorfunction 定义..

        对于 EG:-

        # Define a list
        @arr = qw/rohit jain/; 
        
        # Define a scalar
        $num = 2
        
        # Here perl will evaluate @arr in scalar context and take its length..
        # so, below code will evaluate to : - value = 2 / 2
        $value = @arr / $num;
        
        # Here since it is used with a foreach loop, @arr will be taken as in list context
        foreach (@arr) {
            say $_;
        }
        # Above foreach loop will output: - `rohit` \n `jain` to the console..
        

        【讨论】:

          【解决方案4】:

          您可以通过以下方式强制类型:

          use Scalar::Util qw(dualvar);
          use constant NOTIFY_DIE_MAIL_SEND_FAILED => dualvar 3, 'NOTIFY_DIE_MAIL_SEND_FAILED';
          say NOTIFY_DIE_MAIL_SEND_FAILED;
          say int(NOTIFY_DIE_MAIL_SEND_FAILED);
          

          输出:

          NOTIFY_DIE_MAIL_SEND_FAILED
          3
          

          【讨论】:

            【解决方案5】:

            在这种情况下,Perl 如何知道 exit 需要一个数字参数?

            exit 期望一个数字作为其规范的一部分,如果您向其传递一个非整数值(即您不应该这样做。

            现在,在这种特殊情况下,dualvar 如何根据上下文返回任一值类型?

            我不知道 Scalar::Util 的 dualvar 是如何实现的,但您可以改用 overload 编写类似的东西。

            您当然可以修改受祝福对象的行为:

            #!/usr/bin/env perl
            
            use strict;
            use warnings;
            
            {package Dualvar;
            
            use overload
                fallback => 1,
                '0+' => sub { $_[0]->{INT_VAL} },
                '""' => sub { $_[0]->{STR_VAL} };
            
            sub new {
              my $class = shift;
              my $self = { INT_VAL => shift, STR_VAL => shift };
              bless($self,$class);
            }
            
            1;
            }
            
            my $x = Dualvar->new(31,'Therty-One');
            
            print $x . " + One = ",$x + 1,"\n";    # Therty-One + One = 32
            

            从文档看来,overload 实际上会更改声明范围内的行为,因此您应该能够在本地更改任何操作数的一些常用运算符的行为。

            如果 exit 确实使用这些可重载操作之一将其参数评估为整数,那么这个解决方案就可以了。

            我没有看到像在 Java 中那样为子例程的参数定义数据类型的方法?

            正如其他人已经说过的那样......在 Perl 中不是这种情况,至少在编译时不是这样,除了子例程 prototypes 但这些不提供太多类型粒度(如 int 与字符串或不同的对象类)。

            Richard 提到了一些您可以使用的运行时替代方案。如果您不介意性能损失,我个人会推荐 Moose

            【讨论】:

              【解决方案6】:

              Rohit Jain 所说的是正确的。希望输入遵循某些规则的函数只需明确检查输入是否有效。

              例如

              sub foo 
              {
                  my ($param1,$param2) = shift;
                  $param1 =~ /^\d+$/ or die "Parameter 1 must be a positive integer.";
                  $param2 =~ /^(bar|baz)$/ or die "Parameter 2 must be either 'bar' or 'baz'";
              
                  ...
              }
              

              这可能看起来很痛苦,但是:

              • 获得的额外灵活性通常超过了执行此操作所涉及的工作。
              • 仅仅拥有正确的数据类型通常不足以确保您的输入有效,因此即使使用 Java 之类的语言,您最终也会这样做。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-10-11
                • 2021-06-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-04-27
                • 1970-01-01
                相关资源
                最近更新 更多