0

在 Perl 中,可以为子程序的参数指定数据类型吗?例如,在像 exit 这样的数字上下文中使用 dualvar 时:

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

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

4

6 回答 6

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
}
于 2012-09-25T11:38:56.990 回答
2

dualvar 的全部意义在于它根据您的需要表现为数字或文本。在不明显的情况下(对你来说比对 perl 更重要),然后说清楚。

exit 0 + NOTIFY_DIE_MAIL_SEND_FAILED;

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

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

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

于 2012-09-25T11:43:28.440 回答
1

Perl 与 Java 的不同之处在于 -Perldynamically typed语言,因为它不需要在compile time. 处输入变量,而Javais statically typed(如您所知)

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

只能有two context:-

  • 列出上下文
  • 标量上下文

上下文由使用的operatoror定义function

对于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..
于 2012-09-25T11:35:09.080 回答
1

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

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
于 2012-09-25T11:44:57.707 回答
1

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

exit期望一个数字作为其规范的一部分,如果您传递一个非整数值(即您不应该这样做),它的行为是一种未定义的。

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

我不知道 Scalar::Util 的dualvar是如何实现的,但你可以用重载来编写类似的东西。

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

#!/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

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

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

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

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

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

于 2012-09-27T02:19:56.940 回答
0

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 这样的语言中,您最终还是会做很多这样的事情。
于 2012-09-25T11:44:38.723 回答