How do I declare a class attribute as a union of class names?

时光怂恿深爱的人放手 提交于 2020-04-06 05:00:06

问题


I'm reading a spreadsheet looking for different structures. When I tried the following using Moose it seems to do what I want. I could create different types of objects, assign this to the found member and dump the Cell instance for review.

package Cell
{
  use Moose;
  use Moose::Util::TypeConstraints;
  use namespace::autoclean;

  has 'str_val'    => ( is => 'ro', isa => 'Str', required => 1 );
  has 'x_id'       => ( is => 'ro', isa => 'Str', ); # later required => 1 );
  has 'color'      => ( is => 'ro', isa => 'Str', );
  has 'border'     => ( is => 'ro', isa => 'Str', );
  has 'found'      => ( is => 'rw', isa => 'Sch_Symbol|Chip_Symbol|Net', );
  1;
}

If I try to do the same in Perl 6 it fails to compile.

class Cell {
  has Str $.str_val              is required;
  has Str $.x_id                 is required;
  has Str $.color;
  has Str $.border;
  has Sch_Symbol|Chip_Symbol|Net $.found is rw
}
Malformed has
at C:\Users\Johan\Documents/moose_sch_3.pl6:38
------>   has Sch_Symbol'<'HERE'>'|Chip_Symbol|Net $.found is rw

How can I do this in Perl 6?


回答1:


You could use where

has $.found is rw where Sch_Symbol|Chip_Symbol|Net;

or define new type by subset

subset Stuff where Sch_Symbol|Chip_Symbol|Net;

class Cell {
    has Str   $.str_val is required;
    has Str   $.x_id    is required;
    has Str   $.color;
    has Str   $.border;
    has Stuff $.found   is rw;
}



回答2:


You probably want them to do a common role and specify that as the type

role Common {}
class Sch-Symbol does Common {…}
…

class Cell {
  …
  has Common $.found is rw;
}

Or you will have to use a where constraint

class Cell {
  …
  has $.found is rw where Sch-Symbol|Chip-Symbol|Net;
}

You could also create a subset to wrap the where constraint.

subset Common of Any where Sch-Symbol|Chip-Symbol|Net;

class Cell {
  …
  has Common $.found is rw;
}

Note that a where constraint is slower than using a common role.




回答3:


Here is a fully working implementation of the subset/where solution mentioned by Brad Gilbert in his answer. This includes one example for each of the classes in Common and also one example that shows what happens when type constraints aren't met:

#!/bin/env perl6

class  Sch-Symbol { has Str $.name }
class Chip-Symbol { has Num $.num  }
class         Net { has Int $.id   }

subset Common of Any where Sch-Symbol|Chip-Symbol|Net;

class Cell {
  has Str $.str_val  is required;
  has Str $.x_id     is required;
  has Str $.color;
  has Str $.border;
  has Common $.found is rw;
}

my $str_val = 'foo';
my $x_id    = 'bar';

my @founds = (
    Net.new(:42id),                 # will work
    Sch-Symbol.new(:name<baz>),     # will work
    Chip-Symbol.new(num => 1E101),  # will work
    42,                             # won't work
);

for @founds -> $found {
   my $cell =  Cell.new(:$str_val, :$x_id, :$found);
   dd $cell;
}

Assuming this is in the file test.p6, when we run perl6 test.p6 we get:

Cell $cell = Cell.new(str_val => "foo", x_id => "bar", color => Str, border => Str, found => Net.new(id => 42))
Cell $cell = Cell.new(str_val => "foo", x_id => "bar", color => Str, border => Str, found => Sch-Symbol.new(name => "baz"))
Cell $cell = Cell.new(str_val => "foo", x_id => "bar", color => Str, border => Str, found => Chip-Symbol.new(num => 1e+101))
Type check failed in assignment to $!found; expected Common but got Int (42)
  in submethod BUILDALL at test.p6 line 9
  in block <unit> at test.p6 line 28


来源:https://stackoverflow.com/questions/49660447/how-do-i-declare-a-class-attribute-as-a-union-of-class-names

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!