もちろん、一連の値を組み合わせてより複雑な値にする方法はたくさんあります。それが基本的にデータ構造の研究です。どの特定のデータ構造を選択するかは、かなり複雑な問題であり、実際のユース ケースに大きく依存します。
私はあなたのケースについてほとんど知りませんが、あなたの質問から、これらの属性はすべて同様に構造化された概念を表していることがわかりました。そこで、次の新しいデータ型を作成します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);
}
}
そしてThingWithScale
、オブジェクトに裏打ちされたいくつかの属性を提示しScale
ます。
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);
単純なコンストラクター パラメーターから Scale オブジェクトを自動的にインスタンス化するメソッドを書いていた頃BUILDARGS
、私が本当にやりたかったことは、有効な最小値と最大値を持つ属性を記述する新しい属性トレイトを発明することであることに気付きました。