Почему Perl6 не проверяет длину массива после добавления?

Я определил новый тип Tuple следующим образом:

subset Tuple of Array where { .elems == 2 && .[0] < .[1] };
my Tuple $t = [1, 2];
say $t;  # [1 2] So far, so good.

Я не могу инициализировать его более коротким или длинным массивом или [2, 1], как и ожидалось. Но я могу добавить к нему:

$t.append(3);
say $t;  # [1 2 3] Ouch!

Как такое возможно?


person choroba    schedule 15.08.2016    source источник


Ответы (3)


my Tuple $t создает $t переменную, так что любое (повторное) присвоение или (повторная) привязка к ней должно (повторно) проходить проверку типа Tuple.

= [1, 2] назначает ссылку на объект Array. Применяется Tuple проверка типа (и проходит).

$t.append(3) изменяет содержимое объекта Array, содержащегося в $t, но не переназначает и не связывает $t, поэтому проверка типа отсутствует.

Синтаксис вызова метода изменения - $t.=append(3) вместо $t.append(3) - вызовет проверку типа на $t.

Существует особый синтаксис для массива с проверкой границ (my @array[2] и т. Д.), Но я предполагаю, что это не суть вашего вопроса.

person raiph    schedule 15.08.2016

Ограничение типа привязано к скалярному контейнеру, но содержащийся в нем объект представляет собой простой старый массив, а метод append массива не знает, что вы хотите, чтобы он запускал проверку типа.

Если вы хотите снова явно запустить проверку, вы можете выполнить переназначение, например $t = $t.

person Christoph    schedule 15.08.2016

Если вам действительно нужна измененная версия Array, вы можете просто создать класс, который наследуется от он и переопределяет методы, которые вы хотите вести по-другому. (Вероятно, есть гораздо более элегантные способы сделать это, но это действительно работает):

class Tuple is Array {
    method append ( *@val ) {
        fail '"append" is disabled for Tuples'
    }
}

my $t = Tuple.new(1,2);

say $t;

$t.append(3);

Тогда все будет работать так, как вы ожидаете:

[1 2]
"append" is disabled for Tuples
  in method append at example.p6 line 2
  in block <unit> at example.p6 line 11

Actually thrown at:
  in block <unit> at example.p6 line 11

В качестве альтернативы, чтобы получить что-то подобное, вы можете использовать размерный массив , как указано raiph. Или, если вам просто нужно что-то неизменное, подобное массиву, вы можете использовать _4 _.

person Christopher Bottoms    schedule 16.08.2016