- 论坛徽章:
- 0
|
如下网上找到关于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";
复制代码 |
评分
-
查看全部评分
|