6

我有一个Moose对象:

class My::Game {
  has 'players' => (isa => 'Set::Object', ...)
  has 'action_sequence' => (isa => 'ArrayRef[My::Game::Action]', ...)
}

现在我希望能够通过像$game2 = $game->clone;How do I deep clone it 这样的调用来克隆这个对象,以便克隆 ArrayRef 中的对象?更棘手的是,Set::Object ?

我看过MooseX::Clone,但我不清楚如何将它应用于这种情况。示例代码将不胜感激。

谢谢!

4

2 回答 2

5

我没有使用这里的任何部分(MooseX::CloneMooseX::CompileSet::Object),所以这里只是从我对文档和一般知识的回顾中开始的粗略概述驼鹿建筑:

  • MooseX::Clone 为您的对象提供了一个 clone() 方法,然后该方法将对您的每个具有“克隆”特征的属性调用 clone()。
  • 所以,你需要为你的两个属性添加一个 clone() 方法......
  • 我雄心勃勃地希望MooseX::Clone 可以处理本机属性 arrayrefs,但由于它可能不能,您可以自己扩展该功能(即,如果 'action_sequence' 有选项traits => ['Array'],那么克隆就足够聪明了方法实际上是通过handles => { clone => [ 'map', 'clone' ] }-- 即通过在每个成员元素上调用 clone() 来克隆属性) -- 这可能是您提交第一个补丁的地方
  • Set::Object的文档建议您可以使用Storable::dclone可靠地克隆对象(如果不正确,您应该验证,并鞭打作者和/或提供补丁)
  • 现在您需要向 Set::Object 属性添加一个 clone() 方法,文档建议您使用MooseX::Compile执行此操作(这里是您应该访问 irc.perl.org #moose 并给我们一个逐一记录你的进步,所以我们可以稍后制作一部纪录片):)
于 2010-08-21T16:44:26.903 回答
2

事实证明,简单地将MooseX::Clone角色添加到类中提供了clone()一种递归克隆属性的方法。

  • 对于 hashref/arrayref 属性,它复制结构。
  • 对于标量(包括引用),它只是简单地复制引用。
  • 如果添加traits => ['Clone']到属性,它将通过调用clone()属性值递归地克隆属性。

为了支持 cloning Set::Object,我最终创建了一个CloneByCoercion通过子类化 trait 调用的Clonetrait,参数化为在克隆之前强制转换为/从的类型。

所以为了使用它,我写道:

has 'blah' => (isa => 'Set::Object', is => rw,
  traits => ['CloneByCoercion' => {to=>'ArrayRef'}]
);

MooseX::Types::Set::Object提供与 ArrayRef 之间的强制(尽管我需要修补其中的一个错误:对 ArrayRef 的强制应该返回一个引用,而不是一个列表)

我还进行了修改MooseX::Clone以保留对象可见的散列,以便它支持克隆具有循环引用的互连对象结构。

我最终会把这些东西放在 CPAN 上或向模块提交补丁。

于 2010-08-25T07:35:36.900 回答