如下网上找到关于Moose使用的一个例子,刚接触感觉像天书,网上google一番,看了些资料终于搞明白了。现将整个理解过程简要列一下,希望对大家学Moose有帮助。
-
{
-
package Point;
-
use Moose;
-
-
has 'x' => ( isa => 'Int', is => 'rw' );
-
has 'y' => ( isa => 'Int', is => 'rw' );
-
-
use Moose::Util::TypeConstraints;
-
subtype 'Point::OrHashRef',
-
as 'Point';
-
coerce 'Point::OrHashRef',
-
from 'HashRef',
-
via { Point->new( x => $_->{x}, y => $_->{y} ) };
-
-
sub distance {
-
my $start = shift;
-
my $end = shift;
-
-
my $dx = $end->x - $start->x;
-
my $dy = $end->y - $start->y;
-
return sqrt( $dx * $dx + $dy * $dy );
-
}
-
}
-
-
{
-
package Line;
-
use Moose;
-
-
# And the same for end
-
has ['start', 'end'] => (
-
isa => 'Point::OrHashRef',
-
coerce => 1,
-
is => 'rw',
-
required => 1,
-
trigger => sub {
-
$_[0]->_clear_length();
-
return;
-
}
-
);
-
-
has 'length' => (
-
isa => 'Num',
-
is => 'ro',
-
clearer => '_clear_length',
-
lazy => 1,
-
default => sub {
-
return $_[0]->start->distance( $_[0]->end );
-
}
-
);
-
}
-
-
-
use Test::More;
-
-
my $line = Line->new(
-
start => { x => 1, y => 1 },
-
end => Point->new( x => 2, y => 2 )
-
);
-
isa_ok $line, "Line";
-
isa_ok $line->start, "Point";
-
isa_ok $line->end, "Point";
-
like $line->length, qr/^1.4142135623731/;
-
-
$line->end({ x => 3, y => 3 });
-
like $line->length, qr/^2.82842712474619/, "length is rederived";
-
-
done_testing;
一、弄懂distance函数是如何实现计算两点间的距离的。
1.1将代码简化为:
-
package Point;
-
use Moose;
-
-
has 'x' => ( isa => 'Int', is => 'rw' );
-
has 'y' => ( isa => 'Int', is => 'rw' );
-
-
sub distance {
-
my ( $_, $p ) = @_;
-
#对应例子$p1->distance($p2);
-
#$_->{x}即$p1 = Point->new( x => 4, ... );
-
#$p->{x}即$p2 = Point->new( x => 1, ... );
-
my ( $dx, $dy ) = ( $_->{x} - $p->{x}, $_->{y} - $p->{y} );
-
return sqrt( $dx * $dx + $dy * $dy );
-
}
-
-
package main;
-
my $p1 = Point->new( x => 4, y => 5 );
-
my $p2 = Point->new( x => 1, y => 1 );
-
-
print 'p1与p2相距距离为:';
-
print $p1->distance($p2);
1.2将Moose实现的代码转化为传统OO辅助理解(同为网上找到的例子):
-
sub Point::new {
-
my ($class, $x, $y) = @_;
-
bless [$x, $y], $class; # Implicit return
-
}
-
-
sub Point::distance {
-
my ($self, $from) = @_;
-
#对应例子$p1->distance($p2);
-
#对于传统OO的实现,$self代表$p1,$$self[0]即“bless [$x, $y], $class”中的$x这不难理解了吧,同理$from即传入的$p2。
-
my ($dx, $dy) = ($$self[0] - $$from[0], $$self[1] - $$from[1]);
-
sqrt($dx * $dx + $dy * $dy);
-
}
-
-
my $p1 = Point->new(4, 5);
-
my $p2 = Point->new(1, 1);
-
print $p1->distance($p2);
至此,Line类中length默认值$_[0]->start->distance( $_[0]->end )即为上例$p1->distance($p2)。
2.1弄明白Moose是如何实现自定义类型,并如何强制实现类型转换的。
-
package Point;
-
use Moose;
-
has 'x' => ( isa => 'Int', is => 'rw' );
-
has 'y' => ( isa => 'Int', is => 'rw' );
-
-
#对于new(start => { x => 1, y => 1 },...)函数,我们传给第一个属性的值是个hash引用
-
#但测试输出ok 1 - The object isa Point,转变为了Point对象类型。
-
use Moose::Util::TypeConstraints;
-
#自定义既可以是Point对象类型又可以是HashRef的数据类型,并命名为Point::OrHashRef
-
subtype 'Point::OrHashRef', as 'Point';
-
#将hash引用($hash={ x => 1, y => 1 })强制转换成Point对象,通过Point->new()来实现,$_->{x}即$hash->{x}
-
coerce 'Point::OrHashRef',
-
from 'HashRef',
-
via { Point->new( x => $_->{x}, y => $_->{y} ) };
-
-
package Line;
-
use Moose;
-
-
has [ 'start', 'end' ] => (
-
isa => 'Point::OrHashRef',
-
coerce => 1,
-
is => 'rw'
-
);
-
-
package main;
-
use Test::More;
-
my $line = Line->new(
-
start => { x => 1, y => 1 },
-
end => Point->new( x => 2, y => 2 )
-
);
-
isa_ok $line->start, "Point";
-
isa_ok $line->end, "Point";
阅读(4024) | 评论(0) | 转发(0) |