【问题标题】:Perl: fixing Moose attribute and type coercion problemsPerl:修复 Moose 属性和类型强制问题
【发布时间】:2010-10-15 19:51:52
【问题描述】:

我最近将 Moose 升级到 v1.15,发现我使用的一组模块不再工作。我得到的错误是:

You cannot coerce an attribute (source) unless its type (GOBO::Node) has a coercion at
/opt/local/lib/perl5/site_perl/5.12.0/darwin-multi-2level/Moose/Meta/Role/Application/ToClass.pm line 142

我可以看到几个可能的错误来源,并希望得到有关如何解决问题的建议。

GOBO::Node 的第一段代码如下所示:

package GOBO::Node;
[...]
extends 'GOBO::Base';
with 'GOBO::Labeled';
with 'GOBO::Attributed';

coerce 'GOBO::Node'
  => from 'Str'
  => via { new GOBO::Node(id=>$_) };

has 'source' => (is => 'rw', isa => 'GOBO::Node');

这个包使用的角色也有属性是GOBO::Nodes,错误信息中提到的属性'source'就是其中之一。

  • 在 GOBO::Node 中进行强制转换的部分原因似乎是创建新节点时的捷径。使用 BUILDARGS 而不是强制使用会更好吗?

  • 如果我想要几个包都可以使用强制转换,我应该把它放在哪里?如果我将强制添加到(例如)GOBO::Attributed,我会收到它已经存在的警告。但是,如果没有强制,我会收到上面关于无法强制的警告。

  • 有一个单独的子类型包;创建 GOBO::Node 的子类型会更好吗? GOBO::Node::ProtoNode--和一个强制,并且使用它的属性应该是 GOBO::Nodes?

感谢您对此问题的任何帮助或建议!

【问题讨论】:

    标签: perl moose coercion


    【解决方案1】:

    您粘贴的示例代码实际上并未触发错误。那里写的source 属性不会试图强制任何东西。但是,我假设您提到的角色之一具有定义了 coerce => 1 的属性。

    在 Moose 中,类型和强制转换是全局的。当结合 Moose 动态构建类的事实时,您最终会遇到您在此处看到的奇怪行为。您需要将强制转换的定义移到第一次使用GOBO::Node 类型之前 的某个地方。通常这是通过创建一个子类型包(您注意到您已经拥有)并尽早包含它(通过use)来完成的。

    只需将 GOBO::Node 强制定义移动到此子类型包中,并确保在需要强制的任何地方都使用它即可解决您的问题。

    回答您的其他问题:

    • 一般来说,我建议在BUILDARGS 上使用强制转换,因为它是一个更细粒度的工具。您在此处显示的用法是正确强制使用的教科书示例,因此没有真正的理由要更改它。

    • 如上所述,典型的答案是在单独的命名空间 (MyApp::TypeLibrary) 中构建库包,然后将该包包含在您希望类型可用的类的顶部。 Perl 不会重新编译它已经编译的包,这意味着在这种情况下不会触发你得到的关于已经存在的强制的错误。

    • 根据您提供的示例,无需创建新的子类型,GOBO::Node 应该已经可以工作,并且如果没有新的子类型,这实际上与上一个答案相同。是的,使用子类型库。

    希望对你有帮助。

    【讨论】:

    • 太好了,谢谢 - 并感谢您对其他问题的回答。 :)
    【解决方案2】:

    常见的解决方案是有一个单独的文件来声明类型约束及其强制。如果您需要确保加载了特定的类——例如强制它——在你的强制函数中要求它。

    所以,类似:

    package GOBO::Types;
    use Moose::Util::TypeConstraints;
    class_type 'GOBO::Node';
    coerce 'GOBO::Node',
        from 'Str',
        via { require GOBO::Node; GOBO::Node->new(id => $_) };
    

    您可以在任何地方使用此类型库而不必担心加载顺序,并且您可以确保所有类型都已定义——如果您的类型不是class_type,则尤其重要,因为 Moose 是如何尝试的解析尚未定义的类型约束名称。

    在这里使用强制转换而不是BUILDARGS 绝对是正确的做法;它更易于重复使用。

    【讨论】:

    • 太好了,谢谢!我现在已经修复了问题代码,一切运行顺利。 :D
    猜你喜欢
    • 2014-04-20
    • 2011-09-07
    • 1970-01-01
    • 2016-05-13
    • 2014-12-07
    • 2011-07-04
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多