7

使用 Moose,可以创建具有默认值的属性。我有一组属性,它们都有最小值、最大值和默认值。它们是表示比例的属性(例如 Tk::Scale)。

目前,我至少有 3 个属性:当前和默认值:

has 'attr' => (is => 'rw', isa => 'Int', default => 300, lazy => 1, clearer => '_clear_attr');

分钟:

has 'attr_min' => (is => 'rw', isa => Int', default => 100);

最大限度:

has 'attr_max' => (is => 'rw', isa => Int', default => 1000);

是否可以在一个属性中同时包含所有四个(当前、默认、最小值、最大值)?

4

2 回答 2

7

我认为您想创建一个验证规则。

use Moose::Util::TypeConstraints;

subtype 'ScaleVal',
   as 'Int',
   where { 100 <= $_ && $_ <= 1000 };

has attr => (
   is      => 'rw',
   isa     => 'ScaleVal',
   default => 300,
);
于 2013-05-27T19:32:40.550 回答
1

当然有很多方法可以将一堆值组合成一个更复杂的值——这基本上就是数据结构研究的内容。选择什么特定的数据结构是一个相当复杂的问题,很大程度上取决于您的实际用例。

我对您的情况知之甚少,但我从您的问题中了解到,所有这些属性都代表了类似结构的概念。所以我会创建一个新的数据类型,即Scale

use MooseX::Declare;
class Scale {
    for (qw/min max def/) {
        has $_ => (is => 'ro', isa => 'Num', required => 1);
    }
    has val => (is => 'rw', isa => 'Num', lazy_build => 1);
    method _build_val() {
        return $self->def;
    }
    method BUILD($args) {
        confess "Out of range!" unless $self->_is_in_range($self->val);
    }
    method _is_in_range($val) {
        return defined $val && $val >= $self->min && $val <= $self->max;
    }
    before val ($new_val?) {
        return unless defined $new_val;
        confess "Out of range!" unless $self->_is_in_range($new_val);
    }
}

我会展示一些ThingWithScaleScale对象支持的属性。

class ThingWithScale {
    has _attr => (
        is => 'ro', isa => 'Scale',
        default => sub { shift->_make_attr() },
    );
    method _make_attr($class: $val?) {
        return Scale->new(
            min => 100, max => 1000, def => 200,
            (defined $val ? (val => $val) : ()),
        )
    }
    # Convert `attr` argument to a `Scale` object before passing to real constructor.
    sub BUILDARGS {
        my ($class, %args) = @_;

        if (defined (my $attr = delete $args{attr})) {
            %args = (
                %args,
                _attr => $class->_make_attr($attr)
            );
        }
        return $class->SUPER::BUILDARGS(%args);
    }
}

my $thing = ThingWithScale->new(attr => 101);

大约在我编写该BUILDARGS方法以从简单的构造函数参数自动实例化 Scale 对象时,我意识到我真正想做的是发明一个新的属性特征来描述具有最小和最大合法值的属性。

于 2013-05-30T15:48:14.293 回答