2

Is there some way in Moose to specify that I want an attribute to have a specific type, but also allow there to be a null value (undef?).

For example I am writing a simple implementation of a Linked List and have a Node class where the next and prev pointers are required to be of type Node (this is probably what you would expect)

package Node;
{
   use Moose; 

   has 'value' => (
      is  => 'rw',
      isa => 'Any', # Nodes can be of any type
   );

   has 'prev' => (
      is        => 'rw',
      isa       => 'Node',
      predicate => 'has_prev',
   );

   has 'next' => (
      is        => 'rw',
      isa       => 'Node',
      predicate => 'has_next',
   );

}

But I was hoping to use a sentinel, empty node stored at the head of the list to mark the head, instead of an actual element of the list. So a list of elements [1, 2, 3] would actually look like:

EMPTY -> 1 -> 2 -> 3

I was hoping to be able to specify a empty value (like undef) for the next and prev pointers, but when I create an empty Node in my List class:

package List;
{
   use Moose;

   has 'head' => (
      is      => 'rw',
      isa     => 'Node',
      # empty head node
      default => sub { 
         Node->new( value => undef, next => undef, prev => undef ); 
      }, 
   );

Moose complains because undef is not of type Node.

Is there a way around this ?

4

3 回答 3

5

您可以使用Maybe[type]语法来允许类型或undef. 对于您的示例:

   has 'head' => (
      is      => 'rw',
      isa     => 'Maybe[Node]',
      # empty head node
      default => sub { 
         Node->new( value => undef, next => undef, prev => undef ); 
      }
   );
于 2013-07-08T18:40:28.420 回答
1

下一个:

use 5.014;
use warnings;

package Node {
   use Moose; 
   has 'value' => ( is  => 'rw');
   has 'prev' => ( is => 'rw', isa => 'Undef|Node', predicate => 'has_prev', default=>undef );
   has 'next' => ( is => 'rw', isa => 'Undef|Node', predicate => 'has_next', default=>undef );
}

package List {
   use Moose;
   has 'head' => ( is => 'rw', isa => 'Node', default => sub { Node->new() } );
}

package main;
use Data::Dumper;

my $list = List->new();
say Dumper $list;

印刷:

$VAR1 = bless( {
                 'head' => bless( {
                                    'next' => undef,
                                    'prev' => undef
                                  }, 'Node' )
               }, 'List' );

Moose::Manual::Types对 基本层说:

      Undef     <---- undefined
      Defined
          Value
              Str
                  Num
                      Int
                  ClassName <---- Class name
                  RoleName

稍后在TYPE UNIONS部分中说:

Moose 允许您说一个属性可以是两种或多种不同的类型。例如,我们可能允许使用 Object 或 FileHandle:

有 '输出' => ( is => 'rw', isa => 'Object | FileHandle', );

正如其他人已经说过的,这也是一个Maybe[Something],我不知道什么更好,但Something | SomethingOther看起来更“perlish”(恕我直言)。;)

于 2013-07-08T18:47:54.047 回答
0

作者更Undef|Node喜欢Maybe[Node].

has 'prev' => (
   is        => 'rw',
   isa       => 'Undef|Node',
   predicate => 'has_prev',
);
于 2013-07-08T18:46:13.883 回答