跳转至内容

使用 Moose 编程 / 解决的问题

来自维基教科书,开放世界中的开放书籍

Perl(在 5.10 版本之前)有一个不合逻辑的 **方法解析顺序** (MRO),这在使用多重继承分派时变得明显。对 MI 分派的修复首先在 Dameon 的 NEXT 中流行起来,后来证明是一个有错误的技巧,在许多情况下都失败了。不幸的是,NEXT 被纳入了 Perl v5.7.3 的 CORE 发行版中,并且即使在今天也仍然存在于 CORE 中。Moose 使用更新的、更酷的 C 优化 Class::C3,这是所有大于 Perl 5.95 的 Perl 中正确方法分派的新的非默认标准。[1]

Class::C3NEXT 之前,你有 SUPER,它比 NEXT 早了大约六个月,幸运的是从未进入 CORE。SUPER 非常愚蠢,而且几乎毫无用处,因为如果 foo 和 bar 是 baz 的兄弟姐妹和子类,你就不能在 foo 中重新分派到 bar 中的方法。

本质上,SUPER 只支持线性模式下的方法分派。NEXT 以一种怪异的方式支持它们,而且几乎毫无意义。[2] 在不了解这些怪癖的情况下,新的 Class::C3 很可能正好满足程序员的期望 - 它很直观。Class::C3 使用 C3 MRO 算法,该算法也由 Python 使用。

旧方法

[编辑 | 编辑源代码]

NEXTClass::C3 之间的区别超出了本书的范围;但是,因为普通 Perl 甚至不允许方法解析,以及在 OO 范式意义上的分派,我们将展示 NEXT 来代替它。

一个例子

[编辑 | 编辑源代码]
package A;
use strict;
use warnings;
use NEXT;

sub name {
   my $self = shift;
   $self->{-name} = shift if @_;
   return $self->{-name};
}
sub new {
   my $obj = shift;
   my $class = ref($obj)?ref($obj) : $obj;
   my $args = shift;
   my $self = bless {}, $class;
   $self->{-name} = $args->{name} if( $args && ref($args) eq 'HASH' && $args->{name});
   return $self;
}

sub say_name {
       my $self = shift;
        print "My name is ".$self->name.".\n";
}


package B
use strict;
use warnings;
use NEXT;

our @ISA = 'A'

package C
use strict;
use NEXT;
our @ISA = 'B'

sub say_name {
       my $self = shift;
        print "The name given to me is ".$self->name.".\n";
}


package main;
  my $a = A->new({ name => 'Bob' });
  # prints:
  #  My name is Bob
  $a->say_name;
 
  my $c = C->new({ name => 'Bill' });
  #prints:
  # The name given to me is Bill
  $c->say_name;

调用 Moose

[编辑 | 编辑源代码]

一个例子

[编辑 | 编辑源代码]
  package A;
  use Moose; # Includes strict and warnings
  
  # Define an attribute the object instance has.
  # In this case a name, which has a type of string, and
  #   has a read accessor and a write accessor.
  has name => (  isa => 'Str', is => 'rw' );
  
  sub say_name {
      my $self = shift;
      say " my name is ".$self->name.".\n";
  }
  no Moose; # Clean up the namespace.
  package B;
  use Moose;
  no Moose;
  package C;
  use Moose;
  
  sub say_name {
       my $self = shift;
        say "The name given to me is ".$self->name.".\n";
  }
  no Moose;
  package main;
  
  # We get new for free.
  my $a = A->new({ name => 'Bob' });
  # prints:
  #  My name is Bob
  $a->say_name;
  
  my $c = C->new({ name => 'Bill' });
  #prints:
  # The name given to me is Bill
  $c->say_name;
[编辑 | 编辑源代码]
  1. ^ Perl 5.95 添加了一个新的 pragma mro,它使用 C3 解析。但是,这个 pragma 是可选的,它提供了一些工具给你,所有这些工具都可以使用,同时保持与旧版本的 Perl 的向后兼容性,使用 MRO::Compat。
  2. ^ 那个几乎毫无意义的方法叫做深度优先搜索 (DFS)。DFS 是 Perl 中 C3 之前的 MRO。简而言之,它无法以合理的方式处理任何形式的三角继承。
华夏公益教科书