【问题标题】:How can I validate enum types as Perl subroutine arguments?如何将枚举类型验证为 Perl 子例程参数?
【发布时间】:2009-06-25 10:28:44
【问题描述】:

Does Perl have an enumeration type? 的基础上,我如何执行动态类型检查(或静态类型检查,如果 use strict 能够这样做)我的子例程参数正在获取正确的枚举类型?

package Phone::Type;

use constant {
    HOME => 'Home',
    WORK => 'Work',
};

package main;

sub fun
{
    my ($my_phone_type_enum) = @_;
    # How to check my_phone_type_enum, is either Phone::Type->HOME or Phone::Type->WORK or ... but not 'Dog' or 'Cat'?
}

fun(Phone::Type->HOME); # valid
fun(Phone::Type->WORK); # valid
fun('DOG');             # run-time or compile time error

【问题讨论】:

  • fun('Home')应该有效还是无效?
  • 注意Phone::Type->HOME是类方法调用;如果您希望内联常量,请使用 Phone::Type::HOME。
  • fun('家'); # 理想情况下,它应该是无效的。但是,使用思南Unur提供的解决方案,很难将其标记为无效。所以,我还是可以接受的。不完美,但它适用于我的情况。
  • 您是否声称 fun('Home') 已被我的代码接受?
  • 是的。传递字符串 fun('HOME') 将在您的代码中被接受。

标签: perl enums validation subroutine


【解决方案1】:

这是一种方法:

#!/usr/bin/perl

package Phone::Type;

use strict;
use warnings;

use constant {
    HOME => 'Home',
    WORK => 'Work',
};

package main;

use strict;
use warnings;

sub fun {
    my ($phone_type) = @_;
    Phone::Type->can( $phone_type )
        or die "'$phone_type' is not valid\n";
}

fun('HOME'); # valid
fun('WORK'); # valid
fun('DOG');  # run-time or compile time error
__END__

C:\Temp> dfg
'DOG' is not valid

【讨论】:

  • 但是您传递的是类型的名称,而不是值。这不是我们要求的。
  • 通过使用常量 { HOME => 'HOME', WORK => 'WORK', };使用这种漂亮的语法可以很好地工作:fun(Phone::Type::HOME);但是,当我使用 Readonly.只读我们的 $HOME => 'HOME';只读我们的 $WORK => 'WORK';我尝试使用以下语法调用:fun($Phone::Type::HOME);我得到 'HOME' is not valid 我怎样才能使它也适用于 Readonly?
  • p/s 要添加一些注释,我希望它也适用于 Readonly,因为我的遗留代码的其余部分都使用 Readonly。出于一致性目的。
【解决方案2】:

我建议您使用 Readonly(如引用问题中的建议)而不是常量。我建议使用两种可能的方法(取决于您使用的是 Perl 5.10 还是 5.8)。

最初,相同的代码:

use strict;
use warnings;
use Readonly;

Readonly my @phone_types = qw/HOME WORK/;

Perl 5.10:

sub fun
{
   my $type = shift;
   die "Invalid phone type: $type" unless $type ~~ @phone_types;
   # ...
}

Perl 5.8:

sub fun
{
   my $type = shift;
   die "Invalid phone type: $type" unless grep { $_ eq $type} @phone_types;
   # ...
}

CPAN 上有一个模块可以让您对参数类型和值进行大量控制,但我终生无法记住它。也许其他人可以。

【讨论】:

  • 至少有 Params::Validate 和较新的 MooseX::Types。不过,他们做的事情却大不相同。
  • Params::Validate 是我试图记住的那个。谢谢 :) 不过这种用法可能有点过分了。
【解决方案3】:
package Phone::Type;

my $types;
BEGIN {
    $types = {
        HOME => 'Home',
        WORK => 'Work',
    };
}
use constant $types;

sub is_phone_type {
    my ($type) = @_;
    return exists $types->{$type};
}

package main;
use Carp ();

sub fun
{
    my ($my_phone_type_enum) = @_;
    Phone::Type::is_phone_type( $my_phone_type_enum)
        or Carp::croak "Invalid type $my_phone_type_enum";
}

fun(Phone::Type->HOME); # valid
fun(Phone::Type->WORK); # valid
fun('DOG');             # run-time or compile time error

(BEGIN 是在编译时设置 $types 所必需的,以便它可用于 use 语句。)

在 Perl 中对这样的事情放松是很常见的;假设函数在您期望数字的地方传递数字等。但如果您想做这种验证,您可能对Params::Validate 感兴趣。

【讨论】:

  • 我会在 is_phone_type 中放置一个 eval,以防它通过不是哈希引用的垃圾。答案仍然是错误的。
  • @brian d foy:? is_phone_type 将其输入字符串化,而不是取消引用。
猜你喜欢
  • 2017-04-02
  • 2019-09-19
  • 1970-01-01
  • 2020-08-30
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 2020-10-29
相关资源
最近更新 更多