Предупреждение Вероятно, это nanswer для первоначального намерения OP. В любом случае, я постараюсь ответить на все вопросы, которые будут заданы, прежде чем перейти к финальному nanswer . Полагаю, это делает его частичным безответным.
Хорошо, давайте попробуем ответить на все вопросы по порядку.
сначала почему наследование так работает и
Ну, вы ставите значение в контейнере, тип которого совместим с этим значением. Здесь нет ничего страшного. Это иерархия классов
Иерархия классов
A Hash
is-a
Map
, так что нет проблем с его назначением, верно? Вы могли бы объявить это Cool
, и он все равно не будет жаловаться. Он также не будет жаловаться, если вы просто воспользуетесь my $m
. Но в любом случае тип контейнера будет тем, что он объявлен, а его содержимое все равно будет Hash
; если вы используете say $m.^name
, он все равно вернет Hash
. Давайте go для второго вопроса:
что я могу с этим поделать, если я действительно хочу, чтобы проверка типов гарантировала, что мои неизменяемые переменные останутся такими
Использовать привязку , а не переуступка. В этом случае вы сможете выполнить привязку только в том случае, если тип точно такой же или существует простое приведение. В этом случае вам нужно привязать к map
my $m := Map.new('key', 'value');
Назначая Ha sh на карту, вы на самом деле не заставляете его создавать карту; вы просто используете совместимый контейнер для переменной, которая все еще является картой. Даже если вы привязываете:
my Map $m := Hash.new('key', 'value');
по-прежнему без принуждения, все равно Ha sh. Вам нужно явно принудить (осмелюсь сказать, map
?)
my Map $m := Hash.new('key', 'value').Map;
, и тогда, ну, это будет неизменным. Давайте go к следующему:
Set.isa ('SetHa sh'), Mix.isa ('MixHa sh'), Bag.isa ('BagHa sh '), Blob.isa (' Buf ') и (если учитывается) List.isa (' Array ') все возвращают False
Ну, Map.isa("Hash")
также возвращает False
. Здесь тот же образец. Представьте, что Hash
называется HashMap
. То же самое. Наследование идет только в одном направлении. Вы по-прежнему можете назначить или привязать SetHa sh к переменной Set, вам все равно нужно будет сделать его SetHa sh, чтобы сделать его неизменным.
могу ли я что-нибудь сделать, чтобы получить
Просто назначьте Map
и конвертируйте все, что присвоено Map, или объявите с нуля. Это не приведет к ошибке:
my Map $m where { .WHAT === Map } = Hash.new('key', 0).Map;
# Map.new((key => 0))
Но вы можете просто сказать
my Map $m = Hash.new('key', 0).Map;
В общем, то, что мне действительно нужно, - это способ проверки типов в строгом режиме, поэтому говорить. Если я явно объявлю тип переменной,
ОК, теперь я понимаю, что вы имеете в виду. У Scala есть способ сделать это, вы можете объявить, где значения будут go вверх и вниз по иерархии; Я предполагаю, что это включает в себя полную строгость и разрешение только самого типа. Я не знаю, ошибка ли это, а скорее особенность. И в любом случае я не могу придумать лучшего решения, чем упомянутое вами, за исключением того, что вам, вероятно, нужно будет сделать это для каждой отдельной переменной, которую вы хотите строго ввести, проверить, поскольку она не может быть параметризована (я думаю).